NIO学习(十):Java NIO的零拷贝知识

背景
  1. 在什么地方使用NIO和AIO?
    场景:网络应用编程,需要服务端和客户端。多机之间进行传输数据的场景
  2. 在什么地方使用IO?
    场景单机。不需要服务端和客户端。就是常使用的包装类(Reader, Writer;Inputstream, Outputstream)。
  3. JDK NIO中有FileChannle#transferTo(0, fileChannel.size(), socketChannel)就是一个零拷贝的实例。
  4. JDK NIO中DirectByteBuffer,直接把内存交给操作系统管理,也是零拷贝知识的实例。
  5. 在Netty中对内存的使用,有池化和非池化,然后有堆上内存和堆外内存(直接内存)
  6. 只要是I/O操作,则一定是需要操作系统的API支持。

零知识演变过程
常规IO操作流程

NIO学习(十):Java NIO的零拷贝知识

  1. 操作系统是一个中间桥梁。
  2. 当应用程序(用户空间)发起,操作系统调用读请求(Native方法),内核空间接收到请求后,操作系统切换到内核空间模式,内核空间需要去磁盘上读文件,直接内存访问(DMA)读到内核空间的缓冲区中,然后在拷贝到用户空间的缓冲区中,用户空间然后在进行业务逻辑运算。
  3. 当应用程序(用户空间)发起,系统调用写请求(Native方法),内核空间接收到请求后,操作系统切换到内核空间模式,然后拷贝数据到内核空间的缓冲区,然后从内核空间拷贝到Socket Buffer中,在写数据到客户端。
  4. 4次上下文切换。2次没有必要的拷贝。1次从内核空间拷贝数据到Socket Buffer中。

操作系统上的零拷贝过程

NIO学习(十):Java NIO的零拷贝知识

  1. 应用程序发起了sendfile()的系统调用。
  2. 这里的直接内存是连续的。这样把所有数据放到这块连续的内存中。
  3. 2次上下文切换。1次从内核空间拷贝数据到Socket buffer中。

优化零拷贝实现机制

NIO学习(十):Java NIO的零拷贝知识

  1. 内存是不连续的。
  2. 文件描述符(文件的元信息)的信息存储在socket buffer中。

最好的做法

NIO学习(十):Java NIO的零拷贝知识

  1. 从用户空间切换到内核空间,内核空间读(DMA)磁盘上数据到内核空间(kernel buffer),把文件描述符的数据(文件的元信息)拷贝到socket buffer。protocol engine 从socket buffer中读去文件描述符信息,然后去kernel buffer中读取真正的数据信息。这就是Buffer支持的gathering知识。
  2. 直接内存是不连续的。真实数据在kernel buffer中,文件描述符信息在socket buffer中。通过buffer的gathering功能实现。

小结
  1. 零拷贝?:免去了用户空间和内核空间的数据拷贝过程。这样可以减少了堆上内存,也就减少了Full GC的次数和时间。
  2. 零拷贝其实就是堆外内存,或者理解为直接内存。把原来需要跟用户空间进行数据拷贝的过程省掉,交给操作系统管理。
  3. 零拷贝的实现,需要操作系统提供相应的API支持。
  4. 操作系统是应用程序和外界输入输出设备(Socket I/O)之间的桥梁