什么是零拷贝
零拷贝是一种避免CPU,将数据从一块存储空间拷贝到另一块存储空间的技术。零拷贝技术能够提升应用程序的性能,使得这些应用程序可以更有效的利用系统资源。
零拷贝有什么优点
- 减少CPU拷贝次数,甚至不需要CPU拷贝,从而提升CPU执行效率
- 减少内存的占用
- 减少用户态到核心态之间的上下文切换次数
零拷贝的实现原理
不同的操作系统有不同的实现。这里只介绍Linux系统下的零拷贝实现
- 基于sendfile实现的零拷贝
- 基于mmap实现的零拷贝
基于sendfile实现的零拷贝
- 发出sendfile系统调用,然后用户态切换到内核态(第一次上下文切换);
- 通过DMA将磁盘上的文件拷贝到内核缓冲区(第一次拷贝);
- 然后将数据从内核缓冲区拷贝到socket缓冲区(第二次拷贝)
- sendfile系统调用返回,因此内核态切换回用户态。(第二次上下文切换)通过DMA引擎将内核空间socket缓冲区中的数据传递到协议引擎。(第三次拷贝)
基于sendfile带有DMA收集拷贝功能
- 发出sendfile系统调用,此时用户态切换为内核态(也称为核心态)。通过DMA引擎将磁盘文件中的内容拷贝到内核空间缓冲区中(第一次拷贝)
- 将描述符(内核缓冲区的地址和内核缓冲区的偏移量)发到socket缓冲区(没将具体的数据拷贝到socket)
- sendfile系统调用返回,系统由核心态切换回用户态(第二次切换)。DMA根据socket缓冲区中描述符的信息直接将内核空间缓冲区中的数据拷贝到协议引擎上(第二次拷贝),这样就避免了最后一次CPU数据拷贝。
基于mmap实现的零拷贝
mmap:内存映射是一个比sendfile昂贵但优于传统IO的方法。
- 发出系统调用,导致系统由用户态转成内核态。通过DMA引擎将磁盘文件中的数据拷贝到内核缓冲区中(第一次拷贝)
- mmap系统调用返回,因此发生了第二次上下文切换,由内核态切换回用户态。接着用户空间和内核空间共享这个缓冲区,而不需要将数据从内核空间拷贝到用户空间。因此用户空间就可以像操作自己缓冲区中的数据一样 操作这个内核空间缓冲区的数据。
- 发出write系统调用,导致用户空间到内核空间的上下文切换(第三次上下文切换)。将数据从内核空间缓冲区拷贝到socket缓冲区(第二次拷贝)
- write系统调用返回,系统由核心态转换成用户态(第四次上下文切换)。通过DMA引擎将内核空间socket缓冲区中的数据传递到协议引擎。
通过内存映射mmap实现的零拷贝进行了4次用户空间与内核空间的上下文切换,以及3次拷贝过程,其中包含2次DMA拷贝和1次CPU拷贝,明显与传统IO相比仅仅少了一次CPU拷贝,但是这样做的好处是可以将整个文件或者文件的一部分映射到内存当中,用户直接对内存中的文件进行操作,应用程序只需要处理内存中的数据,这样可以实现非常迅速的IO操作。