一、零拷贝
所谓零拷贝,即不经过CPU的拷贝方式。
1.传统IO
在传统的IO中,拷贝经过以下几个步骤:
拷贝:硬盘->(DMA)内核->(CPU)用户buffer->(CPU)socket buffer->(DMA拷贝)协议引擎
对应的切换模式如下:
切换:用户->内核->用户->内核
图解如下,上图是切换模式,下图是拷贝所需要经过的过程:
其中DMA copy即直接内存拷贝,不经过CPU
2.mmap——内存映射优化
为了减少CPU拷贝,后面提出了MMAP模式。
mmap通过内存映射,将文件映射到内核缓冲区,同时,用户空间可以共享内核空间的数据。
其过程如下:
拷贝:硬盘->(DMA)内核->(CPU)socket buffer->(DMA拷贝)协议引擎
切换模式如下:
切换:用户->内核->内核
其中,我们可以看到,mmap减少了一次cpu拷贝,从内核buffer直接拷贝到socket buffer,同样,减少了一次切换
虽然这样优化了拷贝方式,但并不是真正的零拷贝
3.sendFile函数
直到sendFile的出现,才算真正的零拷贝。
sendFile优化:
Linux2.1提供了sendFile函数,数据不用经过用户态,直接从内核缓冲区进入到SocketBuffer,减少一次切换。
拷贝:硬盘->(DMA)内核->(CPU)socket buffer->(DMA拷贝)协议引擎
切换:用户->内核->内核
sendFile优化:
Linux2.4提供了sendFile函数,数据不用经过用户态,直接从内核缓冲区进入到协议引擎 ,又减少一次切换,实现真正零拷贝(其实也经过了socket buffer,但是拷贝的信息很少,只有length,offset等信息,可忽略)
拷贝:硬盘->(DMA)内核->(DMA拷贝)协议引擎
切换:用户->内核->内核
在netty中应用:transferto函数
二、比较
mmap和sendFile的区别
1.mmap适合小数据量读写,sendFile适合大文件传输
2.mmap至少需要4次上下文切换,3次数据拷贝,sendFile需要3次上下文切换,最少2次数据拷贝
3.sendFile可以利用DMA方式,减少CPU拷贝,mmap则没有。