0%

零拷贝

零拷贝

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

内核空间和用户空间

在说零拷贝之前,先了解一下计算机的内存空间

当前操作系统都是采用的虚拟存储器,对32位操作系统而言,寻址地址为2^32^也就是4G,操作系统将虚拟空间划分为两部分,一部分是内核空间,一部分是用户空间,将最高的1G字节分配给内核使用,称为内核空间;将较低的3G字节供各个进程使用,称为用户空间

内核空间

内核空间主要是指操作系统运行时所使用的用于程序调度、虚拟内存的使用或者连接硬件资源等的程序逻辑

用户空间

由于操作系统中除了操作系统之外,还有运行在操作系统中的用户程序,而每个进程都独立的使用属于自己的内存,为了操作系统的稳定性,运行在操作系统中的用户程序不能访问操作系统所使用的内存空间。

如果用户程序需要访问硬件资源,可以调用操作系统提供的接口来实现,这个调用接口的过程就是系统调用,每一次系统调用都会存在两个内存空间的切换

传统数据读写的过程

  • 第一次数据拷贝,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次上下文切换

适合大文件传输

欢迎关注我的其它发布渠道