C 语言 mmap 内存映射实践
更新时间:2026-08-26。本文是
languages/c/主题专家层文档。read/write是"把数据从内核拷贝到用户态",而mmap是"把文件直接映射进进程地址空间"——之后操作文件就像操作内存一样。这是高性能 IO、零拷贝的基础,也是malloc的底层之一。
本文要回答的问题
mmap和read/write的本质区别是什么?谁更快?MAP_SHARED和MAP_PRIVATE有什么区别?msync是干什么的?什么时候必须调?
一、mmap 是什么
mmap 把文件的某段区域映射到进程的虚拟地址空间,返回一个指针:
c
char *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);之后对 addr 的读写,由内核自动同步到文件(或从文件加载),无需显式 read/write。

二、实测:mmap 写文件
把 64MB 文件映射进来,像写内存一样写:
c
char *addr = mmap(NULL, SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
for (long i = 0; i < SIZE; i++) addr[i] = (char)(i % 256);
msync(addr, SIZE, MS_SYNC); // 刷盘实测:
text
mmap 写 64MB: 40 ms
首字节: 0, 第100字节: 100三、核心 API 与参数
| API | 作用 |
|---|---|
mmap(addr, len, prot, flags, fd, offset) | 映射文件到内存 |
munmap(addr, len) | 解除映射 |
msync(addr, len, flags) | 把映射区的修改刷回磁盘 |
3.1 MAP_SHARED vs MAP_PRIVATE
| flag | 含义 |
|---|---|
MAP_SHARED | 映射的修改写回文件(进程间可见) |
MAP_PRIVATE | 修改不写回文件(写时复制,仅本进程可见) |
3.2 保护位 prot
PROT_READ、PROT_WRITE、PROT_EXEC、PROT_NONE 组合。
四、mmap 的典型场景
| 场景 | 为什么用 mmap |
|---|---|
| 大文件随机访问 | 按需加载,避免一次读入内存 |
| 零拷贝 IO | 省掉"内核→用户态"拷贝 |
| 进程间共享内存 | MAP_SHARED + 匿名映射 |
| 高性能日志/数据库 | 直接写映射区,内核异步刷盘 |
malloc分配大块内存时,底层就是用mmap(匿名映射)而非brk——见 内存分配器原理。
五、常见坑
| 坑 | 说明 |
|---|---|
| 映射区越界 | mmap 的 size 必须 ≤ 文件大小,越界访问 SIGSEGV |
| 忘记 msync | MAP_SHARED 的修改不一定立即落盘,重要数据要 msync |
| SIGBUS | 访问映射区时文件被截断,触发 SIGBUS(不是 SIGSEGV) |
| 泄漏 | munmap 对应 mmap,忘了 unmap 地址空间不释放 |
六、与本站主线衔接
- 零拷贝:mmap 是零拷贝 IO 的基石,见 零拷贝与 sendfile。
- 内存布局:mmap 映射区在进程地址空间的位置,见 内存布局与 ABI。
- 页缓存:mmap 与 page cache 的关系,见 页缓存。
- malloc 底层:brk vs mmap,见 内存分配器原理。
一句话总结
mmap 把文件映射进地址空间,操作内存即操作文件(写 64MB 仅 40ms),省掉了 read/write 的拷贝;MAP_SHARED 写回文件、MAP_PRIVATE 写时复制,重要修改记得 msync 刷盘——这是高性能 IO 和零拷贝的核心工具。