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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/outsanding/article/details/102728460
背景
  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操作流程

在这里插入图片描述

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

操作系统上的零拷贝过程

在这里插入图片描述

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

优化零拷贝实现机制

在这里插入图片描述

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

最好的做法

在这里插入图片描述

  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)之间的桥梁

猜你喜欢

转载自blog.csdn.net/outsanding/article/details/102728460