mmap 把文件当内存来读写,听起来很美。它到底惰性到什么程度?顺序读与随机读各快多少?为什么在 Rust 里它必须是 unsafe?这篇用 RSS 观察、计时和一次真实的 SIGBUS 回答。
映射 16 字节,当作 &[u8] 读:"mmap" 通过 MmapMut 改前 5 字节并 flush 后,用普通 fs::read 读到:"HELLO mmap world"
memmap2 0.9 从 crates.io 下载(需要联网)。普通文件读写见std::fs 文件读写;缓冲读取见BufReader 与缓冲读取。
映射 1 GiB(set_len 创建的稀疏文件)之后 RSS 从 1.9 MB 变成 2.0 MB(映射本身不占物理内存) 写了 2 个字节(分别在文件头和 500 MiB 处)之后 RSS = 2.0 MB 每 4 KiB 读一个字节,遍历全部 262144 个页之后 RSS = 1026.0 MB
RSS 通过 ps 读取,是系统报告值。
mmap 映射(含 map 调用)后直接遍历: 47.8 ms (校验 33552486656) read_to_end 读进 Vec 再遍历: 65.8 ms (校验 33552486656) 1 MiB 缓冲循环读边读边算: 49.7 ms (校验 33552486656)
页缓存已热,没有测冷读。注意:基准里每一轮的结果都要 black_box,否则优化器会删掉没人用的求和,取多轮最小值时会选中被删掉的那一轮,得到接近 0 的耗时(见 Benchmark 一篇)。
mmap 随机读 20 万次: 0.86 ms (校验 10133616913503485778) seek + read_exact 20 万次: 153.93 ms (校验 10133616913503485778)
退出码 -10(负数 = 被信号终止:10),stdout:
映射后读 m[60000] = 7
把文件截断到 4096 字节(另一个句柄/进程也可能这么做)unsafe 的含义见unsafe 的安全边界。