0%

零拷贝

零拷贝

零拷贝是服务器网络编程的关键,常用的零拷贝有mmap和sendFile

传统数据读写的过程

  • 第一次数据拷贝,read调用导致用户态到内核态的一次变化,同时,第一次复制开始:DMA(Direct Memory Access,直接内存存取,即不使用CPU拷贝数据到内存,而是DMA引擎传输数据到内存,用于解放CPU),从磁盘读取文件,将数据放入到内核缓冲区
  • 第二次数据拷贝,即:将内核缓冲区的数据拷贝到用户缓冲区,同时,发生了一次内核态到用户态的上下文切换
  • 第三次数据拷贝,调用write方法,系统将用户缓冲区的数据拷贝到Socket缓冲区,此时,又发生了一次用户态到内核态的上下文切换
  • 第四次数据拷贝,数据异步的从Socket缓冲区,使用DMA引擎拷贝到网络协议引擎,此次不需要进行上下文切换
  • write方法返回,再次从内核态切换到用户态

mmap读写过程

mmap通过内存映射,将文件映射到内核缓冲区,同时,用户空间可以共享内核空间的数据,可以减少内核空间到用户空间的拷贝次数

user buffer和kernel buffer共享,不需要拷贝到用户空间,再从用户空间拷贝到Socket缓冲区,只需从内核缓冲区拷贝到Socket缓冲区即可,将减少一次内存拷贝(3次拷贝),但是不减少上下文切换次数

需要3次数据拷贝,4次上下文切换

适合小数据量读写

sendFile读写过程

sendFile操作数据不经过用户态,直接从内核缓冲区进入到Socket缓冲区,由于不经过用户态,所以减少了一次上下文切换

  • 数据被DMA引擎从文件复制到内核缓冲区
  • 调用write方法从内核缓冲区进入到Socket
  • 数据从Socket缓冲区进入到协议栈

数据进行了3次拷贝,3次上下文切换

Linux2.4版本优化

在Linux2.4版本中,对于sendFile进行了一次调整,避免了从内核缓冲区拷贝到Socket buffer中,而是直接拷贝到协议栈,从而再次减少了一次数据拷贝

  • DMA引擎从文件拷贝到内核缓冲区
  • 从内核缓冲区将数据拷贝到网络协议栈

需要2次数据拷贝,3次上下文切换

适合大文件传输