java NIO零拷贝、顺序读写、MappedByteBuffer

一、顺序读写:

写数据,操作文件时,采用追加的方式。速度非常快(接近内存写的速度)

读数据,也不要自己去seek指定偏移量,而是按顺序read(因为read时会预读取后续一部分数据,而不是仅读取当前位置的数据,所以顺序读可以充分利用预读机制。如果自己seek,那么就无法预读,每次都要去操作本地磁盘)

二、零拷贝

数据拷贝时无需通过JVM内存中转。

当文件1拷贝到文件2时,

(1)如果是非零拷贝,拷贝流程如下:

文件1  >> 操作系统内存1  >>  jvm堆内存1>> 操作系统内存2 >> 文件2

用java的角度理解,相当于:

文件1  >> DirectBuffer1  >>  jvm堆内存1>> DirectBuffer2 >> 文件2

(2)如果是零拷贝,拷贝流程如下:

文件1  >> 操作系统内存1  >>  操作系统内存2 >> 文件2

用java的角度理解,相当于:

文件1  >> DirectBuffer1   >>  DirectBuffer2  >> 文件2

上面的DirectBuffer就是java NIO的堆外内存。

零拷贝少了从操作系统内存1复制到  jvm堆内存中,再从  jvm堆内存复制到操作系统内存2的步骤。而是把数据直接从操作系统内存1由操作系统本身复制到操作系统内存2 ,节省了一次拷贝。

缺点就是:零拷贝时我们java中无法获取和修改DirectBuffer1对应的堆外内存数据,因为这DirectBuffer1只是类比,不一定是java方式创建的,可能是c++或者其他手段所建立的堆外内存,所以拿不到DirectBuffer1。。。所以只能通过该零拷贝把数据从一个地方拷贝到另一个地方而已。。中间DirectBuffer1和DirectBuffer2  在java中无法获取到。

其实看一下FileChannel的transferTo方法源码就知道了,内部最终调用到本地方法了,起码在Java层面没有DirectBuffer1这个对象,自然就无法操作这部分数据。。transferTo最终所调用的本地方法估计就是把DirectBuffer1的数据直接复制到DirectBuffer2中。

为了解决上面缺点,java又有一个MappedByteBuffer,具体请继续看

三、MappedByteBuffer是一种效率低于零拷贝,但高于传统IO的IO操作。

我的另一篇文章:https://blog.csdn.net/qq_36951116/article/details/87308354

关于堆外内存DirectByteBuffer的讲解可以看我另一篇文章:https://blog.csdn.net/qq_36951116/article/details/87185240

参考文章:https://blog.csdn.net/u013096088/article/details/79122671

发布了144 篇原创文章 · 获赞 36 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/qq_36951116/article/details/103991396