原文出自知乎:Java中的零拷贝
Java中的零拷贝
先提出两个问题:
- IO过程中,哪些步骤进行了拷贝?哪些地方零拷贝?
- Java支持哪些零拷贝?
带着这俩问题,我们一起来看下面的探究。
哪里听说过零拷贝?真的0次拷贝吗?
相信大家伙在以往的学习中,或多或少在下面这些组件、框架中有听说过零拷贝 (Zero-Copy)?
Kafka Netty rocketmq nginx apache
什么是零拷贝?
零拷贝(英语: Zero-copy) 技术是指计算机执行操作时,CPU不需要先将数据从某处内存复制到另一个特定区域。这种技术通常用于通过网络传输文件时节省CPU周期和内存带宽。
- 零拷贝技术可以减少数据拷贝和共享总线操作的次数,消除传输数据在存储器之间不必要的中间拷 贝次数,从而有效地提高数据传输效率
- 零拷贝技术减少了用户进程地址空间和内核地址空间之间因为上:下文切换而带来的开销
可以看出没有说不需要拷贝,只是说减少冗余[不必要]的拷贝。
LinuxI/O机制及零拷贝介绍
IO中断与DMA
IO中断,需要CPU响应,需要CPU参与,因此效率比较低。

用户进程需要读取磁盘数据,需要CPU中断,发起IO请求,每次的IO中断,都带来CPU的上下文切换。
因此出现了——DMA。
DMA(Direct Memory Access,直接内存存取) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于CPU 的大量中断负载。 DMA控制器,接管了数据读写请求,减少CPU的负担。这样一来,CPU能高效工作了。 现代硬盘基本都支持DMA。

Linux IO流程
实际因此IO读取,涉及两个过程: 1、DMA等待数据准备好,把磁盘数据读取到操作系统内核缓冲区; 2、用户进程,将内核缓冲区的数据copy到用户空间。 这两个过程,都是阻塞的。

传统数据传送

比如:读取文件,再用socket发送出去 传统方式实现: 先读取、再发送,实际经过1~4四次copy。
buffer = File.read
Socket.send(buffer)
1、第一次:将磁盘文件,读取到操作系统内核缓冲区; 2、第二次:将内核缓冲区的数据,copy到application应用程序的buffer; 3、第三步:将application应用程序buffer中的数据,copy到socket网络发送缓冲区(属于操作系统内核的缓冲区); 4、第四次:将socket buffer的数据,copy到网卡,由网卡进行网络传输。
