java基础--零拷贝

本文详细介绍了Java中的零拷贝技术,包括mmap内存映射和sendFile方法,阐述了它们如何减少数据复制和上下文切换,提高性能。通过实例分析,展示了在不同场景下mmap和sendFile的选择及其优势。
摘要由CSDN通过智能技术生成

零拷贝

零拷贝
  1. 零拷贝是没有cpu拷贝, 从操作系统的角度来说的。因为内核缓冲区之间,没有数据是重复的(只有 kernel_buffer 有一份数据)。
  2. Java 程序中,常用的零拷贝有 mmap(内存映射) 和 sendFile;
  3. 零拷贝不仅仅带来更少的数据复制,还能带来其他的性能优势,如更少的上下文切换,更少的 CPU 缓存伪共享以及无CPU校验和计算;
交互过程:

名词解释: user context:用户态;kernel context:内核态;DMA copy:直接内存拷贝;CPU copy:cpu拷贝

  1. 传统IO
    在这里插入图片描述
    传统IO如上图先将本地文件拷贝到kernel_buffer(内核缓冲区),在经过cup_copy拷贝到user_buffer,数据在user_buffer中进行修改,然后在由user_buffer拷贝到socket_buffer再由DMA_copy拷贝到protocol_engine(协议引擎/协议栈),共经过了4次copy和3次状态切换;

  2. mmap优化在这里插入图片描述mmap 通过内存映射,将文件映射到内核缓冲区,同时,用户空间可以共享内核空间的数据。这样,在进行网络传输时,就可以减少内核空间到用户控件的拷贝次数。如上图先将本地文件拷贝到kernel_buffer(内核缓冲区),kernel_buffer可以共享数据到user_buffer,实现在user_buffer修改共享,再经过cup_copy拷贝到socket_buffer再由DMA_copy拷贝到protocol_engine(协议引擎/协议栈),共经过了3次copy和3次状态切换;

  3. sendFile优化 在这里插入图片描述
    Linux 2.1 版本 提供了 sendFile 函数,其基本原理如下:数据根本不经过用户态,直接从内核缓冲区进入到 Socket Buffer,同时,由于和用户态完全无关,就减少了一次上下文切换,共经过了3次copy和2次状态切换;
    在这里插入图片描述
    Linux 在 2.4 版本中,做了一些修改,避免了从内核缓冲区拷贝到 Socket buffer 的操作,直接拷贝到协议栈,从而再一次减少了数据拷贝。其中kernel_buffer到socket _buffer的cpu_copy信息很少,比如lenght、 offset ,消耗低可以忽略,共经过了2次copy和2次状态切换;

mmap 和 sendFile 的区别

  1. mmap 适合小数据量读写,sendFile 适合大文件传输;
  2. mmap需要3次上下文切换,3次数据拷贝;
  3. sendFile 需要2次上下文切换,最少2次数据拷贝;
  4. sendFile 可以利用 DMA 方式,减少 CPU 拷贝,mmap 则不能(必须从内核拷贝到 Socket 缓冲区)
实例 :

客户端

package com.neei.nio.zeroCopy;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;

/**
 * @param
 * @Author: AaNeei
 * @Date: 2019/12/2  21:47
 * @Description: 游学网
 * @throws:
 */
public class NIOClient {
    public static void main(String[] args) throws IOException {
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.connect(new InetSocketAddress("localhost", 8888));
        //得到一个文件channel
        FileChannel fileChannel = new FileInputStream("xxx.mp4").getChannel();
        //准备发送
        long startTime = System.currentTimeMillis();
        //transferTo 底层使用到零拷贝
        //transfer默认大小8M
        double maxSize = 8 * 1024 * 1024D;
        //向上取整需要拷贝的次数
        int num = (int) Math.ceil(fileChannel.size() / maxSize);
        long transferCount = 0;
        //循环copy大文本
        for (int i = 0; i < num; i++) {
            int count = (int) maxSize;
            if (i == num - 1) {
                count = (int) Math.ceil(fileChannel.size() % maxSize);
            }
            transferCount += fileChannel.transferTo((long) (i * maxSize), count, socketChannel);
        }
        System.out.println("发送的总的字节数 =" + transferCount + " 耗时:" + (System.currentTimeMillis() - startTime));
        //关闭
        fileChannel.close();
    }
}

服务端

package com.neei.nio.zeroCopy;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

/**
 * @param
 * @Author: AaNeei
 * @Date: 2019/12/2  21:39
 * @Description: 游学网
 * @throws:
 */
public class NIOServer {
    public static void main(String[] args) throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        ServerSocket serverSocket = serverSocketChannel.socket();
        serverSocket.bind(new InetSocketAddress(8888));
        ByteBuffer byteBuffer = ByteBuffer.allocate(4096);
        while (true) {
            SocketChannel socketChannel = serverSocketChannel.accept();
            int read = 0;
            while (read != -1) {
                try {
                    read = socketChannel.read(byteBuffer);
                } catch (Exception e) {
                    break;
                }
                byteBuffer.rewind();
            }
        }
    }
}
分析:
  1. 零拷贝相对于传统IO拷贝具有更高的效率,主要体现在减少cpu拷贝,同时也减少了用户态的切换,零拷贝不仅仅带来更少的数据复制,还能带来其他的性能优势,更少的上下文切换,更少的 CPU 缓存伪共享以及无CPU校验和计算
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值