结论:read/write 经过"页缓存 → 用户缓冲区"一次显式拷贝,是同步系统调用;mmap 把文件页直接映射进进程地址空间,访问时按需触发缺页中断加载,访问的是页缓存本身,省掉一次拷贝和缓冲区管理。
展开:差异拆解:1)数据拷贝——read 至少一次内核到用户的拷贝;mmap 零拷贝(直接映射页缓存),这也是零拷贝技术链(sendfile + mmap)的基础。2)内存占用与按需加载——read 一次性把数据搬进用户缓冲;mmap 按需调页,访问哪页加载哪页,适合大文件随机访问。3)系统调用开销——mmap 建立映射后访问是普通内存操作,无系统调用;但每次缺页有 page fault 开销,顺序大吞吐场景下 fault 成本可能反超 read 的拷贝成本。4)落盘时机——mmap 的脏页由内核回写(msync 强制),崩溃一致性语义与 write 不同。选型:随机访问、进程间共享文件、大文件局部访问用 mmap(数据库、Lucene 重度使用);一次性顺序读写、流式处理用 read/write 更可控。易错点:mmap 后文件被其他进程截断,访问越界部分会收到 SIGBUS;madvise 的 MADV_SEQUENTIAL/RANDOM 提示对性能影响显著。
追问方向:sendfile/splice 如何做到完全零拷贝、Java 的 MappedByteBuffer 释放难题(Cleaner 机制)。