一、零拷贝原理
传统io
mmap:
mmap 通过内存映射,将文件映射到内核缓冲区,同时,用户空间可以共享内核空间的数据。这样,在进行网络传输时,就可以减少内核空间到用户控件的拷贝次数。
sendFile:
Linux 2.1 版本 提供了 sendFile 函数,其基本原理如下:数据根本不经过用户态,直接从内核缓冲区进入到 Socket Buffer,同时,由于和用户态完全无关,就减少了一次上下文切换
零拷贝从操作系统角度,是没有cpu 拷贝
sendFile优化:
Linux 在 2.4 版本中,做了一些修改,避免了从内核缓冲区拷贝到 Socket buffer 的操作,直接拷贝到协议栈,从而再一次减少了数据拷贝。具体如下图和小结:
这里其实有 一次cpu 拷贝
kernel buffer -> socket buffer
但是,拷贝的信息很少,比如
lenght , offset , 消耗低,可以忽略
mmap和sendFile的区别:
- mmap适合小数据量读写, sendFile适合大文件传输。
- mmap需要4次上下文切换, 3次数据拷贝: sendFile需要3次上下文切换,最少2次数据拷贝。
- sendFile可以利用DMA方式,减少CPU拷贝, mmap则不能(必须从内核拷贝到Socket缓冲区) 。
二、nio零拷贝
jdk内存拷贝代码:
这里以nio客户端为例:
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("127.0.0.1",1100));
String filePath = "D:\\Netty权威指南第2版.pdf";
FileChannel fileChannel = new FileInputStream(filePath).getChannel();
//在linux下一个transferTo方法就可以完成传输
// 在windows下一次调用transferTo只能发送8m,就需要分段传输文件
// ltransferTto底层使用到零拷贝
fileChannel.transferTo(0,fileChannel.size(),socketChannel);
fileChannel.close();
主要的代码为: fileChannel.transferTo(0,fileChannel.size(),socketChannel);