零拷贝
所谓零拷贝是指将数据直接从磁盘文件复制到网络设备中,而不需要经由应用程序之手,零拷贝大大提高了应用程序的性能,减少了内核和用户模式之间的上下文切换。对于Linux操作系统而言,零拷贝技术以来底层的sendfile
方法实现。对于java应用而言,FileChannal.transferTo()
方法底层实现就是sendfile()
方法
你需要将图片展示给用户,这个情形就意味着需要先将静态图片从磁盘复制出来放到一个内存buf中,然后将这个buf通过套接字(Scoket)传给用户,进而用户获取到图片,这看起来再也正常不过了,但实际上这是低效的流程,我们把上面的的流程抽象成下面的过程:
read(file,tmp_buf,len);
write(socket,tmp_buf,len)
首先调用read()
将静态内容读取到tmp_buf,然后调用write()将tmp_buf写入socket,如图所示:
在这个过程中,需要四次复制的过程
1、调用read()时,文件A中的内容被复制到了内核模式下的read buffer中。
2、CPU控制将内核模式数据复制到用户模式下。
3、调用write()时,将用户模式下的内容复制到内核模式下的Socket buffer中。
4、将内核模式下的Socket Buffer的数据复制到网卡设备中。
从上面的过程可以看出,数据平白从内核模式到用户模式“走了一圈”,浪费了两次复制过程,第一次是内核模式到用户模式;第二次是从用户模式复制到内核模式。内核和用户模式的上下文切换也是4次。
如果采用零拷贝技术,那么应用程序就可以直接请求内核直接从磁盘复制到网络设备中。
零拷贝通过DMA技术将文件内容复制到内核模式下的Read Buffer中,不过没有直接复制到Socket Buffer中,中间经历了两次复制,上下文切换也经历了两次。