Windows用CreateFileMapping/MapViewOfFile、Linux用mmap实现内存映射,需注意句柄/文件描述符显式关闭、映射大小与文件一致、权限匹配及跨平台对齐差异。

Windows下用CreateFileMapping实现内存映射文件
Windows平台最直接的方式是调用Win32 API的CreateFileMapping和MapViewOfFile。它不依赖C++标准库,但必须手动管理句柄和映射生命周期。
常见错误是忘记调用CloseHandle或UnmapViewOfFile,导致句柄泄漏或进程退出后仍占用系统资源;另一个坑是映射大小设得比实际文件小,读写越界却无明显报错,只在访问时触发ACCESS_VIOLATION异常。
- 文件必须先用
CreateFile以GENERIC_READ | GENERIC_WRITE打开,且不能是只读模式(即使只读映射也需可写打开) -
CreateFileMapping的flProtect参数决定访问权限:PAGE_READWRITE对应可读写映射,PAGE_READONLY对应只读,两者不可混用 -
MapViewOfFile返回nullptr时,用GetLastError()查具体原因,常见为ERROR_MAPPED_FILE_SIZE_MISMATCH(映射大小与文件不一致)或ERROR_INVALID_HANDLE(文件句柄无效)
Linux下用mmap映射普通文件
Linux用mmap系统调用,头文件是<sys/mman.h>,映射对象可以是普通文件、设备或匿名内存。文件映射的关键是fd必须有效且支持lseek,比如管道、socket就不行。
容易忽略的是mmap成功后,文件描述符fd仍需显式close()——映射本身不自动关闭文件,不关会导致文件句柄耗尽。
立即学习“C++免费学习笔记(深入)”;
-
prot参数用PROT_READ | PROT_WRITE表示可读写;若文件以只读打开,则PROT_WRITE会失败 -
flags选MAP_SHARED时,修改内存会同步回文件;选MAP_PRIVATE则只写时触发写时复制(COW),不会落盘 - 映射地址建议传
nullptr让内核选择,硬指定地址容易冲突,尤其在ASLR开启时
C++17 std::filesystem配合mmap的典型用法
标准库不提供跨平台内存映射接口,但std::filesystem::file_size和std::filesystem::status能帮你安全获取文件大小和权限,避免mmap或CreateFileMapping因尺寸误判而失败。
比如用std::filesystem::is_regular_file提前过滤掉符号链接或目录,否则Linux下mmap会返回EINVAL,Windows下CreateFile可能打开失败但错误码不直观。
- 映射前务必检查
std::filesystem::file_size(path) > 0,空文件映射虽不报错,但MapViewOfFile可能返回nullptr(Windows)或mmap返回MAP_FAILED(Linux) - 用
std::filesystem::permissions(path, std::filesystem::perms::owner_read)确认读权限,避免因权限不足导致映射失败却被误认为路径错误
跨平台封装要注意的兼容性点
真正难的不是单平台实现,而是把Windows和Linux行为对齐。比如“写入即落盘”在Windows下默认生效(MAP_SHARED等效),Linux下需要额外调用msync;又比如最大映射长度,Windows限制约4GB(32位进程),Linux取决于vm.max_map_area和可用虚拟内存。
- 不要假设
sizeof(void*) == 8就一定能映射大文件——32位程序即使在64位系统上,mmap或CreateFileMapping也会受限于4GB地址空间 - 映射区域的对齐要求不同:Windows要求偏移量是
SYSTEM_INFO.dwAllocationGranularity(通常64KB),Linux要求页对齐(getpagesize(),通常4KB) - 多线程同时映射同一文件时,Windows允许不同视图重叠,Linux下
mmap多次映射同一区域是合法的,但munmap必须配对,不能交叉释放
跨平台代码里最容易被跳过的一步:映射失败后的清理顺序。Windows要先UnmapViewOfFile再CloseHandle,Linux要先munmap再close——反过来可能导致句柄/内存泄漏,且某些系统下后续操作会静默失败。


















