NOTE

4.5 零拷贝机制

1. 传统IO 正常的数据处理流程是这样的: 1. 使用DMA copy(不需要cpu参与)把磁盘中的数据copy到磁盘缓冲区 2. 使用cpu copy把磁盘缓冲区的数据复制到用户区 3. 用户区进行处理 4. 使用cpu copy把 用户区的数据拷贝到Socket缓冲区 5. 使用DMA cop

Operating System / Linux创建于 更新于 historical

这是历史学习笔记,可能存在过时或不完整的理解。

1. 传统IO

Linux IO-直接IO 正常的数据处理流程是这样的:

  1. 使用DMA copy(不需要cpu参与)把磁盘中的数据copy到磁盘缓冲区
  2. 使用cpu copy把磁盘缓冲区的数据复制到用户区
  3. 用户区进行处理
  4. 使用cpu copy把 用户区的数据拷贝到Socket缓冲区
  5. 使用DMA copy(不需要cpu参与)把Socket缓冲区的数据通过socket发送
  6. 调用完毕回到用户态

可以看出传统的IO进行了四次拷贝:1、2、4、5,进行了四次上下文切换:1、2、4、6

2. memory map优化

Linux IO-memory map 通过内存映射技术,把文件映射到内核缓冲区,同时用户空间可以共享内核空间的数据。 步骤如下:

  1. 使用DMA copy(不需要cpu参与)把磁盘中的数据copy到磁盘缓冲区
  2. 磁盘缓冲区和用户区共享数据,用户区进行处理
  3. 使用cpu copy把用户区的数据拷贝到Socket缓冲区
  4. 使用DMA copy(不需要cpu参与)把Socket缓冲区的数据通过socket发送
  5. 调用完毕回到用户态 可以看出memory map进行了三次拷贝:1、3、4,进行了三次上下文切换:1、2、5

3. Linux 2.1 sendfile

Linux IO-Linux 2 步骤如下:

  1. 使用DMA copy(不需要cpu参与)把磁盘中的数据copy到磁盘缓冲区
  2. 使用cpu copy把磁盘缓冲区的数据拷贝到Socket缓冲区
  3. 使用DMA copy(不需要cpu参与)把Socket缓冲区的数据通过socket发送
  4. 调用完毕回到用户态

可以看出Linux 2.1 sendfile进行了三次拷贝:1、2、3,进行了两次上下文切换:1、4

4. Linux 2.6 sendfile

Linux IO-Linux 2 步骤如下:

  1. 使用DMA copy(不需要cpu参与)把磁盘中的数据copy到磁盘缓冲区
  2. 使用cpu copy(这个数据很少很快可以忽略)把磁盘缓冲区的少量数据拷贝到Socket缓冲区
  3. 使用DMA copy(不需要cpu参与)把Socket缓冲区的数据通过socket发送
  4. 调用完毕回到用户态

可以看出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

6. 参考