mappedbytebuffer 多进程共享需同一绝对路径真实文件、统一read_write映射、严格offset/size对齐及手动同步(filelock或原子变量+内存屏障),禁用全量映射与逐字节遍历。

Java NIO 的内存映射文件(MappedByteBuffer)在多进程共享内存通信中,并不自带“开箱即用”的同步或跨进程协调能力,它的极速优势来自操作系统底层的 mmap 机制——多个 Java 进程可映射同一磁盘文件的相同区域,共用物理内存页,从而绕过 socket、管道等传统 IPC 的序列化与拷贝开销。但这个“极速”只在正确使用时成立,否则极易出现数据撕裂、卡顿甚至崩溃。
必须是真实文件,且路径完全一致
Java 没有 Global\ 或命名内存对象的概念,进程间共享靠的是**同一个磁盘文件的绝对路径**。所有进程必须:
- 使用相同路径打开文件(如
/tmp/shared.dat),不能用相对路径或临时文件(Files.createTempFile生成的不可靠) - 确保文件存在且权限允许读写(Linux 注意 umask 和属主;Windows 注意 ACL 和共享锁)
- 避免使用
FileChannel.open(…, StandardOpenOption.DELETE_ON_CLOSE)等会导致文件被删的选项
映射模式与一致性要严格对齐
不同进程若映射模式不一致,通信会静默失效:
- 全部进程必须使用
MapMode.READ_WRITE(READ_ONLY写不了,PRIVATE是 COW,改了不落地也不可见) - 映射的
offset和size必须完全相同,否则逻辑偏移错位,结构体解析全乱 - 强烈建议在映射后立即调用
buffer.order(ByteOrder.nativeOrder()),防止大小端不一致导致 int/long 解析错误
手动同步才是通信安全的核心
mmap 本身不提供同步——它只是让多个进程看到同一块内存,但谁写、谁读、何时读,全靠你控制:
- 推荐用
FileLock(基于文件的 advisory lock)做粗粒度读写互斥,比如写入前channel.lock(),写完force()后释放 - 若需细粒度控制(如 ring buffer 多生产者多消费者),需配合原子整数(
AtomicInteger)+ volatile 标志位 + 显式内存屏障(Unsafe.storeFence()) - 禁止依赖“写完就立刻能读”——即使
force()也不能保证其他进程 CPU 缓存已刷新,必要时加Thread.onSpinWait()或短延时轮询
别碰全量映射和逐字节遍历
2GB 文件调用 channel.map(0, 2L * 1024 * 1024 * 1024) 不会卡,但一旦执行 for (int i = 0; i ,就会触发全部页面缺页加载,瞬间打爆 IO 和内存:
- 按需分段映射:每次只映射 64MB 或 128MB,处理完再 map 下一段
- 批量读写优先:用
buffer.get(byte[])或unsafe.copyMemory()(需开启 Unsafe 权限)替代单字节 get/put - 顺序读大文件?其实
FileChannel.read(ByteBuffer)配 1MB buffer 往往比 mmap 更稳更快,别为“高级感”硬上
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











