什么是零拷贝
零复制(英语:Zero-copy;也译零拷贝)技术是指计算机执行操作时,CPU不需要先将数据从某处内存复制到另一个特定区域。这种技术通常用于通过网络传输文件时节省CPU周期和内存带宽。
传统IO的执行流程
比如想实现一个下载功能,服务端的任务就是:将服务器主机磁盘中的文件从已连接的socket中发出去,关键代码如下:
while((n = read(diskfd, buf, BUF_SIZE)) > 0)
write(sockfd, buf , n);
传统的IO流程包括read以及write的过程:
read:将数据从磁盘读取到内核缓存区中,在拷贝到用户缓冲区
write:先将数据写入到socket缓冲区中,最后写入网卡设备
流程图如下:
1.应用程序调用read函数,向操作系统发起IO调用,上下文从用户态切换至内核态
2.DMA控制器把数据从磁盘中读取到内核缓冲区
3.CPU把内核缓冲区数据拷贝到用户应用缓冲区,上下文从内核态切换至用户态,此时read函数返回
4.用户应用进程通过write函数,发起IO调用,上下文从用户态切换至内核态
5.CPU将缓冲区的数据拷贝到socket缓冲区
6.DMA控制器将数据从socket缓冲区拷贝到网卡设备,上下文从内核态切换至用户态,此时write函数返回
从流程图中可以看出传统的IO流程包括4次上下文的切换,4次拷贝数据(两次CPU拷贝以及两次DMA拷贝)
什么是上下文切换
什么是上下文
CPU 寄存器,是CPU内置的容量小、但速度极快的内存。而程序计数器,则是用来存储 CPU正在执行的指令位置、或者即将执行的下一条指令位置。它们都是 CPU 在运行任何任务前,必须的依赖环境,因此叫做CPU上下文。
什么是上下文切换
它是指,先把前一个任务的CPU上下文(也就是CPU寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。
一般我们说的上下文切换,就是指内核(操作系统的核心)在CPU上对进程或者线程进行切换。进程从用户态到内核态的转变,需要通过系统调用来完成。系统调用的过程,会发生CPU上下文的切换。
零拷贝给我们带来的好处
- 减少甚至完全避免不必要的CPU拷贝,从而让CPU解脱出来去执行其他的任务
- 减少内存带宽的占用
- 通常零拷贝技术还能够减少用户空间和操作系统内核空间之间的上下文切换
零拷贝的实现
零拷贝实际的实现并没有真正的标准,取决于操作系统如何实现这一点。零拷贝完全依赖于操作系统。操作系统支持,就有;不支持,就没有。
如何实现零拷贝
零拷贝并不是没有拷贝数据,而是减少用户态、内核态的切换次数以及CPU拷贝次数;实现零拷贝主要有三种方式分别是
1.mmap + write
2.sendfile
3.带有DMA收集拷贝功能的sendfile
什么是DMA
DMA,英文全称是Direct Memory Access,即直接内存访问。DMA本质上是一块主板上独立的芯片,允许外设设备和内存存储器之间直接进行IO数据传输,其过程不需要CPU的参与。
简单的说它就是帮住CPU转发一下IO请求以及拷贝数据,那为什么需要它呢?其实主要是效率问题。它帮忙CPU做事情,这时候,CPU就可以闲下来去做别的事情,提高了CPU的利用效率。大白话解释就是,CPU老哥太忙太累啦,所以他找了个小弟(名叫DMA) ,替他完成一部分的拷贝工作,这样CPU老哥就能着手去做其他事情。
下面看下DMA具体是做了哪些工作
1.用户应用程序调read函数,向操作系统发起IO调用,进入阻塞状态等待数据返回
2.CPU接到指令后,对DMA控制器发起指令调度
3.DMA收到请求后,将请求发送给磁盘
4.磁盘将数据放入磁盘控制缓冲区并通知DMA
5.DMA将数据从磁盘控制器缓冲区拷贝到内核缓冲区
6.DMA向CPU发送数据读完的信号,CPU负责将数据从内核缓冲区拷贝到用户缓冲区
7.用户应用进程由内核态切回用户态,解除阻塞状态
什么是虚拟内存
现代操作系统使用虚拟内存,即虚拟地址取代物理地址,使用虚拟内存可以有2个好处:
1.虚拟内存空间可以远远大于物理内存空间
2.多个虚拟内存可以指向同一个物理地址
正是多个虚拟内存可以指向同一个物理地址,可以把内核空间和用户空间的虚拟地址映射到同一个物理地址,这样的话,就可以减少IO的数据拷贝次数,示意图如下