最大的坑是将posix与windows内存映射语义误认为“差不多”:mmap返回指针,windows需createfilemapping+mapviewoffile配对;windows无map_shared/map_private等价机制,匿名映射不兼容;文件句柄/生命周期绑定不同,对齐要求迥异(64kb vs 页对齐),混写必然导致数据一致性错误、资源泄漏或运行时崩溃。

为什么不能直接用 mmap 和 CreateFileMapping 混写
跨平台内存映射封装最大的坑,是把 POSIX 和 Windows 的语义当成了“差不多”。mmap 返回的是指针,CreateFileMapping + MapViewOfFile 才算配对;但 Windows 下没有匿名映射的等价物(INVALID_HANDLE_VALUE + SEC_COMMIT 仅模拟部分行为),而 POSIX 的 MAP_SHARED/MAP_PRIVATE 在 Windows 上根本不存在对应机制。直接桥接会导致数据一致性错误,尤其在多进程写场景下。
- Linux/macOS:必须用
open+mmap,文件句柄和映射生命周期强绑定 - Windows:必须用
CreateFile+CreateFileMapping+MapViewOfFile,三者缺一不可,且UnmapViewOfFile后仍需CloseHandle显式释放映射对象 - 大小对齐:Windows 要求映射偏移和长度都按
SYSTEM_INFO.dwAllocationGranularity对齐(通常是 64KB),POSIX 只要求页对齐(getpagesize())
MapRegion 类怎么设计才不踩内存泄漏和句柄泄漏
核心是把平台差异收进构造/析构,而不是暴露裸 API。不要用 RAII 封装单个系统调用(比如只管 mmap),而要封装整个“映射生命周期”——从打开/创建文件,到映射,再到解除映射和关闭。
- 构造函数里完成全部平台相关初始化:
fd或hFile、映射对象句柄(Windows)、映射地址(统一存为void*) - 析构函数必须按反序清理:POSIX 先
munmap再close;Windows 先UnmapViewOfFile,再CloseHandle(hMap),最后CloseHandle(hFile) - 禁止拷贝,只支持移动:
MapRegion管理唯一资源,拷贝会导致双 free 或句柄重复关闭 - 提供
data()和size()接口,屏蔽底层指针/长度计算逻辑(比如 Windows 实际映射长度可能被向上对齐)
如何安全支持只读、读写、追加式写入三种模式
跨平台“读写”不是简单设 PROT_READ | PROT_WRITE 和 PAGE_READWRITE 就完事。关键在文件打开权限、映射保护标志、以及是否允许截断/扩展文件大小。
- 只读映射:POSIX 用
O_RDONLY+PROT_READ;Windows 用GENERIC_READ+PAGE_READONLY—— 注意 Windows 若用PAGE_READWRITE但文件只读打开,MapViewOfFile会失败 - 读写映射:POSIX 需
O_RDWR,且文件必须存在并有写权限;Windows 必须用GENERIC_READ | GENERIC_WRITE,且映射对象创建时用PAGE_READWRITE - 追加写(如日志):POSIX 可
lseek+write扩展文件再映射;Windows 必须先SetFilePointerEx+SetEndOfFile,否则MapViewOfFile可能映射不到新增区域
映射失败时怎么给出可定位的错误信息
不同平台错误码完全不兼容:mmap 失败返回 MAP_FAILED,errno 含具体原因;Windows 函数失败返回 NULL,需调用 GetLastError()。统一错误处理必须转换为枚举或字符串,不能只打 printf("mmap failed")。
- 封装层内部记录最后一次失败的平台原错误码(
errno或GetLastError()),提供last_error()接口 - 常见错误需翻译:比如
EINVAL(POSIX)对应ERROR_MAPPED_FILE_SIZE_ZERO(Windows),都表示“试图映射空文件” - 调试时建议输出原始错误码+字符串:
Failed to map: errno=12 (ENOMEM) / GetLastError=8 (ERROR_NOT_ENOUGH_MEMORY)
跨平台内存映射真正难的不是调用 API,而是对齐语义、生命周期和错误边界。哪怕只支持单进程访问,也要小心 Windows 的句柄泄漏和 POSIX 的 MAP_POPULATE 与 MAP_LOCKED 不可用性——这些细节不会报编译错误,但会在高负载时突然崩掉。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











