纯粹作为在Netty课程中关于零拷贝的笔记输出,各位看官勿喷!
- 在linux操作系统中,JVM在用户空间下向内核空间发送read命令,并切换至内核态,内核向硬盘灯其他硬件设备读取对应的数据至内核缓冲当中,这里就产生了第一次数据拷贝;
- 数据准备完毕之后,操作系统由内核态转到用户态,并将内核缓冲中的数据拷贝至用户空间的缓冲区当中,这里就产生了第二次数据拷贝;
- 当数据拷贝完成之后,用户空间向内核发送write命令,并且换至内核态,将数据从用户空间拷贝到内核缓冲区,这里就产生了第三次数据拷贝,
- 当数据拷贝完成之后,内核需要将数据从内核缓冲拷贝至socket缓冲区,并切换至用户态,这就产生了第四次数据拷贝;
- 最后当socket缓冲数据完毕之后,会将数据拷贝至协议引擎,并发送至网络,这就产生了第五次数据拷贝;
而在当前的描述过程中可以看出,用户空间中的缓冲区仅仅作为了一个数据媒介,并没有发挥任何的作用,这样就造成了一些不必要的数据拷贝以及性能丢失,所以JVM利用操作系统的另一个底层命令,将不必要的操作进行优化。
- 在linux操作系统中,JVM在用户空间下向内核空间发送sendfile命令,并且换至内核态,内核从硬件中读取数据至内核缓冲区,这就产生了第一次数据拷贝;
- 当数据在内核空间准备完成之后,内核直接将数据拷贝至socket缓冲区,这就产生了第二次数据拷贝,并从内核态切换至用户态;
- 当socket缓冲区的数据准备完成之后,将数据拷贝至协议引擎,并发送至网络,这就产生了第三次数据拷贝;
随着操作系统发展,人们发现,其实在内核中发生一次拷贝也是可以省略的,即(将内核缓冲区的数据拷贝至socket缓冲区),它只是将内核缓冲区的描述符写入socket缓冲区,而协议引擎中的数据通过内核缓冲区和socket缓冲区进行Gather操作,即完成数据的拷贝,这样就免去了一次数据拷贝,实现了真正意义上的零拷贝。