在学习Netty框架的时候接触到了零拷贝,在此对理解零拷贝的过程做以总结
首先要学习零拷贝,要对计算机的底层原理有一定了解,要先搞清楚什么是用户空间,什么是内核空间。
1.对用户空间,内核空间,上下文切换的理解
计算机为了保证操作系统能够安全稳定地运行,专门将一部分内存分为用户空间,一部分内存分为内核空间。涉及到计算机底层的一些指令,或者安全性强的指令,就会交给用户空间来执行例如文件的拷贝,网络的连接与断开等。用户的一些应用程序的指令,就会在用户控件中执行。而用户空间到内核空间的切换就称为上下文切换。
2.传统IO
而通过传统的socket和IO流传输文件时,就需要先把文件从磁盘加载到内核空间,再从内核空间加载到用户空间。在用户空间可以对文件做一些操作,然后再传给内存空间,最终由内存空间把文件发送到协议栈,再回到用户空间继续执行程序。期间一共经历了4次上下文切换,4次IO。

这样一来消耗了大量的内存资源,造成了资源浪费,性能堪忧...可以通过两种方式来进行优化,一种是使用mmap即内存映射,另一种是用Linux在2.4版本提供的sendFile函数进行优化。而Linux在这一版提供的sendFile函数即是真正意义上的 零拷贝。下面对这两种优化方式,及零拷贝做以解释。
3.mmap优化
mmap通过内存映射,将内核缓冲区的文件映射到用户空间,使得用户空间可以共享内核空间的映射文件,这样一来就省去了将内核空间的文件拷贝到用户空间的步骤。文件被加载到内核空间之后,做一次内存映射,之后直接拷贝到socket缓冲区,再发送给协议栈。IO过程中经历了4次上下文切换,3次IO,但这还不是真正意义的零拷贝,因为还存在一次CPU拷贝。如下图:

4.sendFile优化
Linux2.1版本提供了sendFile函数,数据不需要经过用户空间,直接通过内核空间就可以完成拷贝。文件被加载到内核空间之后,不用再做映射到用户空间的操作,直接拷贝到socket缓冲区,发送给协议栈。期间一共2次上下文切换,3次拷贝。

Linux2.4版本对sendFile函数做了一些优化,将文件从内核缓冲区拷贝到SocketBuffer的操作被优化为只传输少量标志位等信息到SocketBuffer。这样一来文件就可以直接从内核空间拷贝到协议栈。只需要2次上下文切换,2次拷贝,实现了真正意义上的零拷贝。

总结:
1.零拷贝是从操作系统的角度来理解的,所以只有不存在CPU拷贝(内核空间拷贝到内核空间)的时候才能称为零拷贝
2.零拷贝是网络编程的关键,对性能优化很重要
3.mmap适合少量数据读写,sendFile适合大文件传输
4.sendFile可以以DMA的方式实现零拷贝,而mmap则不能(必须从内核拷贝到SocketBuffer中)


浙公网安备 33010602011771号