news 2026/5/1 6:29:56

java中使用mmap技术简介

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
java中使用mmap技术简介

前言

jdk21 之后,随着 FFM 加入并稳定,现在 java 中也可以直接使用 mmap 技术将文件直接映射进内存并读取了,并且没有 nio 中 21 亿的限制(Integer.MAX_VALUE)。

BIO时代

try (FileInputStream fis = new FileInputStream("file.txt")) { byte[] buffer = new byte[8192]; // 8KB 缓冲区 int bytesRead; while ((bytesRead = fis.read(buffer)) != -1) { // 处理 buffer 中的前 bytesRead 字节 } }

最早读取文件就是阻塞读取,由于 byte[] 是jdk管理,自己传入的,所以下标最大就是21亿,而且由于正常情况下由代码传入,所以不可能 new byte[Integer.MAX_VALUE],而且 byte[] 回收需要看 gc。

NIO时代(JDK 1.4+)

try (FileChannel channel = FileChannel.open(Paths.get("data.txt"), StandardOpenOption.READ)) { MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, size); }

后来 java 推出了 NIO,但是作者本人实际工作接触的需要如此优化的场景太少,且 api 并不直观,导致完全没有用过几次。返回的 MappedByteBuffer api 中下标参数使用的是 int,这直接导致超过 4G 的文件必须分段映射,且 MappedByteBuffer 映射的内存也需要 gc 回收。

属于初代 mmap 技术,虽然原理上是 mmap,但是限制颇多。

AIO时代(JDK 7+)

本质上是 NIO.2,或者叫 new NIO,原则上属于NIO的一部分

AsynchronousFileChannel

这个 api 更是查无此人,作者并不知道这个应该怎么用/有什么性能。

FFM(JDK 22+)

try (var arena = Arena.ofConfined(); var channel = FileChannel.open(path, StandardOpenOption.READ)) { var size = channel.size(); var memorySegment = channel.map(FileChannel.MapMode.READ_ONLY, 0, size, arena ); } catch (IOException e) { throw new RuntimeException(e); }

随着 FFM 稳定,原本的 FileChannel api 中也加入了对 FFM 的支持,使用 Arena 配置接下来申请的内存的生命周期管理,再将 arena 传入 channel,返回 MemorySegment,使用 MemorySegment 即可对全文件进行随机读写。arena 关闭后申请的所有内存直接回收,没有 gc 压力。

由于调用的是底层的 mmap 返回的内存段,所以直接读写 memorySegment 即可直接反应到文件上,也可以调用 MemorySegment#force() 强制写入。

更加接近底层的 mmap 技术,可选择是否有 gc 压力。

读取示例:

public class MemorySegmentFileTest { private static final Path path = Path.of("/home/bin-/Downloads/home/extraData.img"); static void main() { try (var arena = Arena.ofConfined(); var channel = FileChannel.open(path, StandardOpenOption.READ)) { var size = channel.size(); var memorySegment = channel.map(FileChannel.MapMode.READ_ONLY, 0, size, arena ); System.out.println("成功映射文件,大小:" + printSize(size)); System.out.println("内存段地址:" + memorySegment.address()); System.out.println("内存段大小:" + printSize(memorySegment.byteSize())); System.out.println("内存段内容前16字节:"); for (long i = 0; i < 16; i++) { byte b = memorySegment.get(ValueLayout.JAVA_BYTE, i); System.out.printf("0x%02X ", b); } System.out.println(); System.out.println("内存段内容后16字节:"); for (long i = size - 16; i < size; i++) { byte b = memorySegment.get(ValueLayout.JAVA_BYTE, i); System.out.printf("0x%02X ", b); } System.out.println(); } catch (IOException e) { throw new RuntimeException(e); } } private static String printSize(long size) { String[] units = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}; long s = size; var list = new ArrayList<String>(); var builder = new StringBuilder(); var formatter = new Formatter(builder); for (var unit : units) { int sub = (int) (s & ((1 << 10) - 1)); formatter.format("%s %s", sub, unit); list.add(builder.toString()); builder.setLength(0); if (s < 1024) { break; } s >>= 10; } return String.join(" ", list.reversed()); } }

原理说明

mmap 只是建立了虚拟内存地址到磁盘文件的映射,并没有真正加载数据(Lazy Loading)。只有真正读取数据时,OS 才会发生缺页中断(Page Fault)去加载数据。

类似应用

  • 数据库系统:SQLite、MySQL、Redis
  • Kafka
  • RocketMQ

已知缺点

  • 本质是在借用 OS 的 Page Cache,如果同时运行数据库(MySQL/Redis)等应用,java 使用 mmap 疯狂读取大文件可能会把数据库在 Page Cache 里的热数据挤出去(Eviction)。

结尾

本文只是提出一种新版本 jdk 的全新 mmap 使用方式,与其他相对较老的方式相比,这种方式可以直接操纵堆外内存,且性能更高,还支持随机读取,唯一缺点可能就是 api 太新,用起来可能需要重新研究写法。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 8:29:47

九大权威论文查重工具测评:提升学术原创性的必备指南

核心工具对比速览 工具名称 核心功能 处理时间 适配检测平台 特色优势 aibiye 降AIGC查重 20分钟 知网/格子达/维普 保留学术术语的AI痕迹弱化 aicheck AIGC检测降重 即时 主流学术平台 实时检测反馈精准降重 askpaper 学术AI优化 15-30分钟 高校常用系统 专…

作者头像 李华
网站建设 2026/4/26 14:22:32

30岁转行AI,是否可行?大模型学习全攻略:从零基础到AI专家的逆袭之路

文章讲述了一位非技术背景人士如何成功转型AI领域。作者分享了三点核心经验&#xff1a;AI领域普通人在边缘地带也有机会&#xff1b;过去的技能是进入新领域的宝贵财富&#xff1b;转型需先上车再找座、在工作中融合、用作品说话。同时提供了大模型AI的完整学习路径&#xff0…

作者头像 李华
网站建设 2026/4/9 22:26:27

告别手动刷新!用RssHub+cpolar搭建24小时自动追更神器

RssHub 的核心功能是为各类网站生成标准化 RSS 订阅源&#xff0c;无论是社交媒体动态、学习平台课程更新还是技术社区内容&#xff0c;都能被统一抓取并推送至阅读器&#xff0c;无需手动刷新多个页面。它的适用人群覆盖较广&#xff0c;自媒体人可追踪热点、技术爱好者能关注…

作者头像 李华
网站建设 2026/5/1 6:27:51

如何解决跨平台字体显示难题?PingFangSC字体的全面应用指南

如何解决跨平台字体显示难题&#xff1f;PingFangSC字体的全面应用指南 【免费下载链接】PingFangSC PingFangSC字体包文件、苹果平方字体文件&#xff0c;包含ttf和woff2格式 项目地址: https://gitcode.com/gh_mirrors/pi/PingFangSC 在数字化设计领域&#xff0c;字体…

作者头像 李华