Netty学习二之深入理解NIO中的零拷贝

实际工作中:我们经常将磁盘上的文件读取到程序或内存中,然后以字节数组或流的方式发送传输出去

我们经常的操作是:将文件以流的方式去读取到buffer,这种操作操作系统(linux)的底层到底是怎么操作的

首先设计到io的操作,一定是调用的native方法

Netty学习二之深入理解NIO中的零拷贝_第1张图片

场景:我们从磁盘中读取数据,然后将数据读到内存中,将内存中的数据写到 网络的另一端

处理过程:


当我们程序发起读取文件的命令,我们的用户空间 会将系统调用命令 发送给内核空间,然后操作系统  由 用户空间切换为内核空间
内核 空间模式上真正的向磁盘发出请求,通过dma 将磁盘数据读入到内核空间的缓冲切(内核空间缓冲区用户不能直接使用,这个是第一次copy)
然后将数据从内核空间copy 到用户的缓冲区中,

然后我们需要将数据写到网路的另外一端

write需要文件数据从用户空间缓冲区 拷贝到内核缓冲区(这里的内核缓冲区和上面的不一样,是socket的换中去中),然后将数据写入到网络
然后操作完成

整个过程中存在四次上下文的切换(即不同空间之间的切花)和两次的不必要的数据copy

 

这个过程中,我们没有将数据处理,所以用户空间 只不过是个载体,这种就是传统的inputStream,outputStream

零拷贝完全取决于操作系统,系统提供这种机制,那就可以使用

nio的零copy可以提升性能:

Netty学习二之深入理解NIO中的零拷贝_第2张图片

内核空间收到sendfile的系统调用后,将磁盘上的数据,让后读到内核缓冲区,然后将数据复制socket缓冲区中(所以从操作系统角度上,实现了零copy,但是仍然存在copy过程)

 

当操作系统支持支持scatter和gather时,我们还可以继续优化,取消copy的过程(linux2.4版本以后)

Netty学习二之深入理解NIO中的零拷贝_第3张图片

一般来说硬件都有直接内存访问的机制,都期望地址是连续的,内核去请求数据,根据内核直接访问机制(或者用scatter和gather  或者操作系统提供了文件描述的机制,描述符描述了偏移量数据大小),这样socket 可以直接通过file的describer去探测到内核缓冲区是什么样的,就不需要去赋值

Netty学习二之深入理解NIO中的零拷贝_第4张图片

在上述过程中我们没有参与内核空间和磁盘 ,socket之间的过程,如果需要我们参与这个工程,我们需要磁盘映射文件

java中用MappedByteBuffer,修改内存就可以同步修改文件,文件的本身映射到内核空间,我们的应用程序可以访问内核文件,就好像文件在内
核空间一样

 

 

 

你可能感兴趣的:(IO)