Java 零拷贝

 2023-02-06
原文作者:蒋先森 原文地址:https://jlj98.top/

Linux 传统的数据传输,一般需要涉及到数据的4次copy。这4次copy,分别是两次用户态和内核态之间Copy需要CPU参与,两次内核态和IO设备间的copy为DMA方式不需要CPU的参与。零拷贝技术主要就是减少用户态和内核态间copy数据次数。

比如我们现在需要把实现一个场景:从一个文件中读取数据并将数据发送到另一台服务器上。从上图中看出:

202212301147295151.png

  • 应用程序调用 read 方法,这里会涉及到一次上下文切换(用户态->内核态),底层采用DMA 读取磁盘文件数据,并把内容存储到内核地址空间的读取缓存。
  • 由于应用程序无法读取内核地址空间的数据,如果需要程序操作这些数据,必须把数据从读取缓冲区拷贝到用户缓冲区。这时,read()调用返回,引发一次上下文切换(内核态->用户态),这样就把数据拷贝到用户地址空间缓冲区了。这样应用程序就可以操作这些数据了。
  • 我们的目的是需要把数据发送到另外一个服务器,调用Socket的send()方法,这时候又涉及到一次上下文的切换(用户态->内核态),同时文件数据被进行第三次拷贝,再次从用户地址空间拷贝到内核地址空间缓冲区。
  • send() 调用返回,引发第四次上下文切换,同时进行第四次的数据拷贝,通过DMA把数据从目标套接字相关的缓存区传输到协议引擎进行发送。

在上面的图中,1和4是有DMA负责,不需要CPU参与,但是过程2和3需要CPU的参与。从这样流程中,我们会发现,如果不需要再应用程序中操作文件数据,其中2和3的步骤是多余的,直接把内核态数据读取后直接拷贝到套接字相关的缓冲区,就能提升性能。这就是零拷贝技术。

零拷贝技术可以减少数据拷贝和共享总线操作的次数,消除传输数据在存储器之间不必要的中间拷贝次数,从而有效地提高数据传输效率。零拷贝技术减少了用户应用程序地址空间和操作系统内核地址空间之间因为上下文切换而带来的开销。

Java 层实现零拷贝