mmap 是 C++ 读取大文件最高效手段之一,因其避免多次系统调用与内存拷贝,通过虚拟内存映射实现按需加载和 O(1) 随机访问,配合 page cache 提升重复读取性能。

用 mmap 读取大文件是 C++ 中最高效的手段之一,尤其适合只读、随机访问或需要处理 GB 级以上文件的场景。它避免了传统 read() 或 std::ifstream 的多次系统调用和内存拷贝,直接将文件“映射”进进程地址空间,让读取变成指针访问。
为什么 mmap 比传统读取快?
核心优势在内核层面: mmap 不复制文件内容到用户缓冲区,而是建立虚拟内存页与磁盘页的映射关系;真正访问某段数据时才按需触发缺页中断并加载(lazy loading);操作系统还自动管理缓存(page cache),重复读取不走磁盘。
对比:std::ifstream 逐块 read + memcpy,小块读取开销大;大 buffer 又占内存且无法跳转;而 mmap 支持 O(1) 随机定位,比如直接 data[1024*1024*100] 访问第 100MB。
基础 mmap 用法(Linux/macOS)
关键步骤:打开文件 → 获取大小 → mmap 映射 → 使用 → munmap + close
立即学习“C++免费学习笔记(深入)”;
- 用
open()以O_RDONLY打开,避免写时拷贝(COW)开销 - 用
lseek() + read()或stat()精确获取文件大小(mmap 需指定长度) -
mmap(nullptr, len, PROT_READ, MAP_PRIVATE, fd, 0):推荐MAP_PRIVATE(只读映射,写操作会触发 SIGBUS,安全) - 映射成功后,返回指针可像数组一样访问,例如解析二进制结构体:
auto hdr = reinterpret_cast(mapped_ptr); - 务必检查返回值是否为
MAP_FAILED,并用munmap()释放映射(不释放不会泄露,但浪费虚拟地址空间)
Windows 上等效方案:CreateFileMapping + MapViewOfFile
Windows 没有 mmap,但语义一致:
-
CreateFile打开文件(GENERIC_READ+FILE_SHARE_READ) -
CreateFileMapping创建映射对象(PAGE_READONLY) -
MapViewOfFile获取可访问指针(类似 mmap 返回值) - 用完调
UnmapViewOfFile和CloseHandle(顺序不能反)
跨平台可封装一层宏或工具类,判断 _WIN32 或 __linux__ 分支处理。
实用技巧与避坑点
不是所有情况都适合 mmap: 小文件(MAP_SHARED(同步到磁盘代价高);32 位程序注意虚拟地址空间不足(建议 64 位编译)。
- 想提升启动速度?用
madvise(ptr, len, MADV_WILLNEED)提前通知内核预读(Linux) - 读完就扔?
MADV_DONTNEED让内核回收物理页(不释放虚拟地址) - 确保文件不被外部修改:映射期间其他进程 truncate 或 write 可能导致 SIGBUS —— 只读打开 + 文件权限控制更稳妥
- C++ RAII 封装很必要:用
unique_ptr配合自定义 deleter(调munmap),避免裸指针泄漏
不复杂但容易忽略:mmap 是高效工具,不是银弹。用对场景、配合适当提示、做好错误检查,就能稳定扛住几十 GB 日志或数据文件的快速解析任务。











