C++怎么使用内存映射_C++mmap文件映射【高效】

1次阅读

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

C++怎么使用内存映射_C++mmap文件映射【高效】

怎么用 mmap 把文件映射进内存

直接调 mmap 就行,但得配对用 openclose,不能传普通 FILE*。常见错误是忘了 open 要加 O_RDWRO_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::vectorstd::String 包裹映射区——它们会尝试管理内存,和 mmap 冲突
  • 线程访问同一映射区?自己加锁,mmap 本身不提供同步

为什么有时 mmapread

小文件、随机访问少、或者只读一次时,mmap 反而更重:它要建立 VMA、触发缺页中断、TLB 填充。真正快的场景是:大文件 + 多次访问 + 局部性好(比如解析二进制协议、内存数据库索引)。

性能陷阱:

  • 频繁 msync(MS_SYNC)?磁盘 I/O 会卡住主线程,能异步就用 MS_ASYNC
  • 映射后没用 madvise(MADV_WILLNEED) 预热,首次访问延迟高
  • 32 位程序地址空间紧张,映射多个大文件容易 ENOMEM

映射本身不加载数据到物理内存,第一次访问才 page fault——这个延迟在低延迟场景里得实测,不能只看文档说“零拷贝就快”。

text=ZqhQzanResources