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

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

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

- 内存是不连续的。
- 文件描述符(文件的元信息)的信息存储在socket buffer中。
最好的做法

- 从用户空间切换到内核空间,内核空间读(DMA)磁盘上数据到内核空间(kernel buffer),把文件描述符的数据(文件的元信息)拷贝到socket buffer。protocol engine 从socket buffer中读去文件描述符信息,然后去kernel buffer中读取真正的数据信息。这就是Buffer支持的gathering知识。
- 直接内存是不连续的。真实数据在kernel buffer中,文件描述符信息在socket buffer中。通过buffer的gathering功能实现。
小结
-
零拷贝?:免去了用户空间和内核空间的数据拷贝过程。这样可以减少了堆上内存,也就减少了Full GC的次数和时间。
- 零拷贝其实就是堆外内存,或者理解为直接内存。把原来需要跟用户空间进行数据拷贝的过程省掉,交给操作系统管理。
- 零拷贝的实现,需要操作系统提供相应的API支持。
-
操作系统是应用程序和外界输入输出设备(Socket I/O)之间的桥梁。