内存映射文件是怎么工作的?什么时候快、有什么限制?这篇用 1 GB 的文件实测 RSS 的变化、随机读速度、映射与普通读写的可见性和边界(Direct ByteBuffer 与堆外内存在前面的篇目)。
已生成 1024 MB 的文件
映射 1 GB 文件前 RSS = 40 MB,map() 之后 RSS = 44 MB(只是建立了地址映射,没有读文件) 每隔 64 KB 读 1 个字节(只碰到 1/16 的页)之后 RSS = 301 MB 每页都碰一次之后 RSS = 1079 MB(整个文件进了进程的驻留内存统计)
顺序读 1 GB(逐字节求和):通过映射 645 ms;FileChannel.read(1 MB 缓冲)后逐字节 718 ms 随机读 1048576 个 8 字节:通过映射 getLong 16 ms(15 ns/次);RandomAccessFile.seek+readFully 1052 ms(1003 ns/次) (文件在操作系统页缓存里,没有测冷读盘)
通过映射写入 m.put(0, 77)、m.putInt(100, 123456),没有调用 force():另一条路径 Files.readAllBytes 读到 [0] = 77,[100..103] 的 int = 123456(同一个页缓存,立刻可见) 再通过 FileChannel.write 在 5 号位置写 99:映射里 m.get(5) = 99(两个方向都互相可见) 第二个映射写 m2.put(200, 55):第一个映射里 m.get(200) = 55 force() 之后:数据被要求写回磁盘(是否真的落盘本篇没有验证掉电场景) 越过映射范围写 m.put(5000):IndexOutOfBoundsException READ_ONLY 映射写入 → ReadOnlyBufferException
READ_ONLY 映射 3 GB(超过 Integer.MAX_VALUE):IllegalArgumentException: Size exceeds Integer.MAX_VALUE READ_ONLY 映射超出文件大小的范围:IOException: Channel not open for writing - cannot extend file to required size 文件 100 字节,READ_WRITE 映射 1 MB:映射之后文件大小 100 → 1048576(READ_WRITE 映射会把文件扩到映射范围) 映射着的文件被 Files.delete 之后:映射仍然可读 m.get(0) = 0,文件已存在吗:false(这是 macOS 上的结果)