spark||flink||scalaElasticsearchkafka,netty,mmap,页缓存,缓存中间件

JAVA IO专题三:java的内存映射和应用场景

2021-02-26  本文已影响0人  挡不住的柳Willow

相关java IO专题

JAVA IO专题一:java InputStream和OutputStream读取文件并通过socket发送,到底涉及几次拷贝
JAVA IO专题二:java NIO读取文件并通过socket发送,最少拷贝了几次?堆外内存和所谓的零拷贝到底是什么关系
JAVA IO专题三:java的内存映射和应用场景
JAVA IO专题四:java顺序IO原理以及对应的应用场景

mmap的作用

mmap的作用,是将文件的一部分直接映射到内存(堆外内存),对这个映射的操作会由操作系统在某个特定的时期自动将脏页写回文件对应的位置(也可以通过msync强制写回),而不必调用read/write。mapp完成后,OS并没有直接读取文件的内容,而是在真正要访问的时候,通过缺页异常来进行读磁盘操作。

mmap相比普通的文件读写优势在哪

常规文件操作为了提高读写效率和保护磁盘,使用了页缓存机制。这样造成读文件时需要先将文件页从磁盘拷贝到页缓存中,由于页缓存处在内核空间,不能被用户进程直接寻址,所以还需要将页缓存中数据页再次拷贝到内存对应的用户空间中。

而mmap实现了将设备驱动在内核空间的部分地址直接映射到用户空间,使得用户程序可以直接访问和操作相应的内容,减少了额外的拷贝。

说白了,mmap的关键点是实现了用户空间和内核空间的数据直接交互而省去了空间不同数据不通的繁琐过程。因此mmap效率更高。

mmap不适合的场景

mmap也不是万能的:

java中mmap的应用

java中提供了MappedByteBuffer支持mmap的调用,其本身是一个DirectByteBuffer,即堆外内存。获取MappedByteBuffer方式如下:

MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, fileSize);

另外MappedByteBuffer扩展了一个force方法,强制将buffer中的内容写入磁盘。

java内存映射的应用场景

消息队列的场景非常契合前面说到的mmap的优势,并且能够完美避开其劣势。java开源消息队列RocketMQ和QMQ都采用了MappedByteBuffer写消息数据,以顺序写的方式提高吞吐量。这里举QMQ为例(RocketMQ笔者不太了解hhh):

//这里的workingBuffer是堆内存,初始化了一些header数据
targetBuffer.put(workingBuffer.array(), 0, headerSize);
//这里的nioBuffer是netty接收到的消息,默认为堆外内存
targetBuffer.put(message.getBody().nioBuffer());

参考文章

Linux 中 mmap() 函数的内存映射问题理解
认真分析mmap:是什么 为什么 怎么用

上一篇下一篇

猜你喜欢

热点阅读