简述Linux零拷贝原理

什么是零拷贝

零拷贝描述的是在计算机操作系统中,CPU不执行将数据从一个内存区域,拷贝到另一个内存区域的任务。
通过网络传输文件时,零拷贝通常可以节省CPU周期和内存带宽。

零拷贝的好处

  1. 节省了CPU周期,空出的周期可以完成其它任务。
  2. 减少内存区域间的数据拷贝,节省内存带宽。
  3. 减少用户态和内核态之间的数据拷贝,提升数据传输效率。
  4. 减少用户态和内核态之间的上下文切换。

零拷贝原理

传统IO中,用户态和内核态空间之间的复制是完全没有必要的,因为用户态空间仅仅起到一种数据转存媒介的作用,除此之外没有做任何事情。

传统I/O

通过传统socket和I/O流传输文件时,需要先把文件从磁盘加载到内核空间,再从内核空间加载到用户空间。在用户空间可以对文件做一些操作,然后再传给内核空间,最终由内核空间把文件发送到协议栈,再回到用户空间继续执行。4次上下文切换,4次I/O。

Linux提供sendfile()减少数据拷贝和上下文切换次数

Linux2.1版本的sendfile()函数

  1. 发起sendfile()系统调用,操作系统由用户态空间切换到内核态空间(第一次上下文切换)
  2. 通过DMA引擎将数据从磁盘拷贝到内核态空间的输入socket缓冲区中(第一次拷贝)
  3. 将数据从内核空间拷贝到与之关联的socket缓冲区(第二次拷贝)
  4. 将socket缓冲区的数据拷贝到协议引擎中(第三次拷贝)
  5. sendfile()系统调用结束,操作系统由内核态空间切换到用户态空间(第二次上下文切换)

根据以上过程,一共产生了2次上下文切换和3次I/O拷贝。减少了从用户空间到内核空间以及相反的2次拷贝,从操作系统的角度来看,这就是零拷贝
内核空间出现复制的原因:通常硬件在通过DMA访问时期望的是连续的内存空间。

Linux2.4版本sendfile()函数

Linux2.4对sendfile()做了一些优化,将文件从内核缓冲区拷贝到socket缓冲区的操作(上述步骤3)被优化为只传输少量标志位信息到socket缓冲区。这样来文件可以直接从内核空间拷贝到协议栈。2次上下文,2次拷贝。

mmap零拷贝原理

mmap通过内存映射,将内核缓冲区的文件映射到用户空间,使用户空间可以共享内核空间 的映射文件,这样来省去了将内核空间的文件拷贝到用户空间的步骤。文件被加载到内核空间后,做一次内存映射,之后直接拷贝到socket缓冲区,再发送给协议栈。4次上下文切换,3次拷贝。但这不是真正意义上的零拷贝,因为还存在一次CPU拷贝

总结

  • 零拷贝是从操作系统的角度来理解的,所以只有不存在CPU拷贝(内核空间拷贝到内核空间)才能称为零拷贝。
  • 零拷贝是网络编程的关键。
  • mmap适合少量数据读写,sendfile适合大文件传输。
  • sendfile可以以DMA的方式实现零拷贝,而mmap不能。
posted @ 2023-03-01 16:27  yytarget  阅读(173)  评论(0编辑  收藏  举报