MappedByteBuffer高性能的核心在于交由操作系统管理I/O,实现零拷贝、按需分页、共享映射和本地内存直通;其映射内存属堆外,不归GC管,需谨慎控制大小并适时force()刷盘。

Java 中 MappedByteBuffer 的高性能,核心不在 Java 层代码多精巧,而在于它把文件 I/O 的控制权交还给了操作系统,并绕过了 JVM 堆内存和传统系统调用的数据搬运路径。
零拷贝:跳过内核缓冲区中转
传统 read()/write() 调用至少涉及两次数据复制:磁盘 → 内核页缓存 → 用户缓冲区(读),或用户缓冲区 → 内核页缓存 → 磁盘(写)。MappedByteBuffer 则让进程的虚拟内存页直接指向文件在磁盘上的物理页——访问时触发缺页异常,由内核一次性将对应文件页加载进物理内存,后续读写直接操作该内存页。整个过程没有用户态与内核态之间的数据拷贝,真正实现“零拷贝”语义(严格说是零显式拷贝)。
按需分页:大文件不占满实际内存
映射一个 10GB 文件,并不会立刻占用 10GB 物理内存。操作系统以页为单位(如 4KB)管理映射区域,只有当你真正读写某个位置时,才会触发缺页中断,加载对应文件页到内存。未访问的区域只保留虚拟地址映射关系,不消耗物理内存。这使得处理远超堆内存大小的文件成为可能,且内存使用高度稀疏、可控。
共享映射与跨进程可见性
当多个 Java 进程(或 Java 与其他语言进程)以 READ_WRITE 模式映射同一文件的相同区域,它们看到的是同一块物理内存页。一个进程写入后,其他进程可立即读到变更(无需额外同步机制),这是操作系统级的内存共享。数据库的 WAL 日志、消息队列的持久化存储、高频交易系统的低延迟共享状态,都依赖这一特性。
立即学习“Java免费学习笔记(深入)”;
本地内存直通:脱离 GC 管控但需自主管理
MappedByteBuffer 背后的内存是直接从本地堆外(native memory)分配的,不属于 JVM 堆,因此不受 GC 回收。这意味着:
- 写入性能稳定,无 GC 暂停干扰;
- 但映射过大或过多,会耗尽本地内存,抛出
OutOfMemoryError: Map failed; - 没有
close()或unmap()方法,释放依赖于对象被 GC 回收 + JVM 退出,生产环境需避免长期持有大映射对象。
刷盘时机由 OS 决策,force() 是双刃剑
写入 MappedByteBuffer 后,数据先落在内存页中,何时写回磁盘由操作系统根据脏页策略决定(如周期性回写、内存压力触发等)。调用 buffer.force() 可强制同步当前映射区域的脏页到磁盘,但这是阻塞式系统调用,频繁使用会抵消 mmap 的性能优势,仅应在关键数据落盘强一致场景下谨慎使用。



















