用 mmap 映射文件需先 open(配 o_rdonly/o_rdwr),再调 mmap,检查返回值是否为 map_failed(查 errno),用 munmap 和 close 配对释放;map_private 修改不落盘,map_shared 才同步。

怎么用 mmap 把文件映射进内存
直接调 mmap 就行,但得配对用 open 和 close,不能传普通 FILE*。常见错误是忘了 open 要加 O_RDWR 或 O_RDONLY,结果 mmap 返回 MAP_FAILED。
典型流程:
int fd = open("data.bin", O_RDWR);void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);- 检查
addr == MAP_FAILED,别直接解引用 - 用完调
munmap(addr, size),再close(fd)
MAP_PRIVATE 修改不写回文件,MAP_SHARED 才会同步——这点常被忽略,改了以为存了,其实没落盘。
mmap 失败返回 MAP_FAILED 怎么查原因
不是所有失败都打印错误,得自己查 errno。最常见的是:EINVAL(offset 不对齐或 size=0)、ENOMEM(虚拟地址空间不足,尤其在 32 位程序里)、EPERM(文件没读/写权限,或挂载时用了 noexec)。
立即学习“C++免费学习笔记(深入)”;
调试建议:
- 用
strace -e trace=mmap,munmap,open看系统调用实际参数和返回值 - 确认
size是页对齐的?不用手动对齐,mmap内部会向上取整到页大小,但 offset 必须是页对齐的(getpagesize()) - 大文件映射失败?试试
MAP_NORESERVE避免预分配 swap 空间(Linux 特有)
C++ 里怎么安全封装 mmap 避免裸指针泄漏
别手写 RAII 类去 new/delete 映射地址——mmap 分配的是虚拟内存,必须用 munmap 释放。正确做法是用 std::unique_ptr 配自定义 deleter:
auto mmap_deleter = [size](void* p) { munmap(p, size); };
using mmap_ptr = std::unique_ptr<std::byte[], decltype(mmap_deleter)>;
mmap_ptr data{static_cast<std::byte*>(addr), mmap_deleter};
注意点:
- deleter 捕获的
size必须是 const 或 move 进去,不能是局部变量引用 - 别用
std::vector或std::string包裹映射区——它们会尝试管理内存,和mmap冲突 - 多线程访问同一映射区?自己加锁,
mmap本身不提供同步
为什么有时 mmap 比 read 慢
小文件、随机访问少、或者只读一次时,mmap 反而更重:它要建立 VMA、触发缺页中断、TLB 填充。真正快的场景是:大文件 + 多次访问 + 局部性好(比如解析二进制协议、内存数据库索引)。
性能陷阱:
- 频繁
msync(MS_SYNC)?磁盘 I/O 会卡住主线程,能异步就用MS_ASYNC - 映射后没用
madvise(MADV_WILLNEED)预热,首次访问延迟高 - 32 位程序地址空间紧张,映射多个大文件容易
ENOMEM
映射本身不加载数据到物理内存,第一次访问才 page fault——这个延迟在低延迟场景里得实测,不能只看文档说“零拷贝就快”。









