news 2026/6/10 17:19:38

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/5/30 21:50:16

7个技巧掌握鸿蒙远程调试与跨设备控制:HOScrcpy实战指南

7个技巧掌握鸿蒙远程调试与跨设备控制&#xff1a;HOScrcpy实战指南 【免费下载链接】鸿蒙远程真机工具 该工具主要提供鸿蒙系统下基于视频流的投屏功能&#xff0c;帧率基本持平真机帧率&#xff0c;达到远程真机的效果。 项目地址: https://gitcode.com/OpenHarmonyToolkit…

作者头像 李华
网站建设 2026/5/12 3:14:22

干掉if-else噩梦!这四种设计模式太优雅了!!

在日常开发中&#xff0c;我们经常会遇到需要根据不同条件执行不同逻辑的场景&#xff0c;导致代码中出现大量的 if/else 嵌套。这不仅降低了代码的可读性和可维护性&#xff0c;还会增加后续扩展的难度。 本文将介绍四种优雅的设计模式来优化这种"条件爆炸"问题&am…

作者头像 李华
网站建设 2026/6/4 13:34:20

OpCore Simplify实战指南:解决黑苹果配置难题的5个非传统方案

OpCore Simplify实战指南&#xff1a;解决黑苹果配置难题的5个非传统方案 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 作为一名长期探索黑苹果系统…

作者头像 李华
网站建设 2026/5/21 3:45:02

测试工程师的进化论:从质量守门人到数字业务赋能者

——基于技术演进与市场需求的深度行业分析 一、被误读的“岗位消亡论”&#xff1a;技术迭代下的认知迷雾 2025年末&#xff0c;AI辅助测试工具覆盖率已达78%&#xff08;Gartner数据&#xff09;&#xff0c;自动化脚本生成技术突破60%应用场景。当部分从业者焦虑于“测试将…

作者头像 李华
网站建设 2026/5/26 2:12:09

开发转行AI教育:零经验启动的3个步骤

在当今数字化转型浪潮中&#xff0c;人工智能&#xff08;AI&#xff09;教育已成为高增长领域&#xff0c;预计到2030年&#xff0c;全球AI教育市场规模将突破2000亿美元&#xff08;来源&#xff1a;麦肯锡报告&#xff09;。对于软件测试从业者而言&#xff0c;这一转型并非…

作者头像 李华