NOTE
4.5 零拷贝机制
1. 传统IO 正常的数据处理流程是这样的: 1. 使用DMA copy(不需要cpu参与)把磁盘中的数据copy到磁盘缓冲区 2. 使用cpu copy把磁盘缓冲区的数据复制到用户区 3. 用户区进行处理 4. 使用cpu copy把 用户区的数据拷贝到Socket缓冲区 5. 使用DMA cop
这是历史学习笔记,可能存在过时或不完整的理解。
1. 传统IO
正常的数据处理流程是这样的:
- 使用DMA copy(不需要cpu参与)把磁盘中的数据copy到磁盘缓冲区
- 使用cpu copy把磁盘缓冲区的数据复制到用户区
- 用户区进行处理
- 使用cpu copy把 用户区的数据拷贝到Socket缓冲区
- 使用DMA copy(不需要cpu参与)把Socket缓冲区的数据通过socket发送
- 调用完毕回到用户态
可以看出传统的IO进行了四次拷贝:1、2、4、5,进行了四次上下文切换:1、2、4、6
2. memory map优化
通过内存映射技术,把文件映射到内核缓冲区,同时用户空间可以共享内核空间的数据。
步骤如下:
- 使用DMA copy(不需要cpu参与)把磁盘中的数据copy到磁盘缓冲区
- 磁盘缓冲区和用户区共享数据,用户区进行处理
- 使用cpu copy把用户区的数据拷贝到Socket缓冲区
- 使用DMA copy(不需要cpu参与)把Socket缓冲区的数据通过socket发送
- 调用完毕回到用户态 可以看出memory map进行了三次拷贝:1、3、4,进行了三次上下文切换:1、2、5
3. Linux 2.1 sendfile
步骤如下:
- 使用DMA copy(不需要cpu参与)把磁盘中的数据copy到磁盘缓冲区
- 使用cpu copy把磁盘缓冲区的数据拷贝到Socket缓冲区
- 使用DMA copy(不需要cpu参与)把Socket缓冲区的数据通过socket发送
- 调用完毕回到用户态
可以看出Linux 2.1 sendfile进行了三次拷贝:1、2、3,进行了两次上下文切换:1、4
4. Linux 2.6 sendfile
步骤如下:
- 使用DMA copy(不需要cpu参与)把磁盘中的数据copy到磁盘缓冲区
- 使用cpu copy(这个数据很少很快可以忽略)把磁盘缓冲区的少量数据拷贝到Socket缓冲区
- 使用DMA copy(不需要cpu参与)把Socket缓冲区的数据通过socket发送
- 调用完毕回到用户态
可以看出Linux 2.6 sendfile进行了两次拷贝:1、3,进行了两次上下文切换:1、4
5. 零拷贝是什么
CPU不需要为数据在内存之间的拷贝消耗资源。说白了就是cpu copy次数为0

5.1. Java中的零拷贝
- Netty的FileRegion,底层源码调用NIO的FileChannel.transferTo方法实现
- JDK NIO ByteBuffer.allocateDirect的堆外内存
- JDK NIO FileChannel.map:底层使用Linux的mmap
- JDK NIO FileChannel.transferTo: 底层使用Linux的sendfile