linux下只读mmap需设prot_read、优选map_private;windows需createfile+createfilemapping+mapviewoffile三步,权限严格匹配;两者均需注意大文件映射的系统限制与首次访问才加载数据的特性。

Linux 下用 mmap 映射大文件为只读内存
Linux 上实现只读内存映射,核心是 mmap 的 prot 参数设为 PROT_READ,且 flags 避免写入相关标志(如 MAP_SHARED 配合 PROT_WRITE 会触发写时复制或权限冲突)。实际使用中,多数只读场景应优先选 MAP_PRIVATE ——它不回写、不依赖文件可写权限,还能避免 mmap 失败于只读挂载点。
常见错误是误传 PROT_READ | PROT_WRITE 却未 open 文件为可写,导致 mmap 返回 MAP_FAILED 并置 errno = EACCES;或用 MAP_SHARED 映射只读文件,内核直接拒绝。
-
open()用O_RDONLY即可,无需O_RDWR -
mmap()的length可小于文件大小,但偏移量offset必须是页对齐(getpagesize()的整数倍) - 映射成功后,对内存区域写入会触发
SIGSEGV,不是静默忽略 —— 这是只读保护生效的明确信号 - 记得
munmap(),否则泄漏虚拟内存地址空间(尤其在 long-running 进程中)
Windows 下用 MapViewOfFile 实现只读映射
Windows 路径稍长:先 CreateFile 打开文件(GENERIC_READ 权限),再 CreateFileMapping 创建映射对象(PAGE_READONLY),最后 MapViewOfFile(FILE_MAP_READ)。三步缺一不可,任一环节权限不匹配都会失败。
典型卡点是 CreateFileMapping 的 flProtect 和 MapViewOfFile 的 dwDesiredAccess 必须兼容:比如 flProtect = PAGE_READONLY 时,dwDesiredAccess 只能是 FILE_MAP_READ 或 FILE_MAP_COPY;若错传 FILE_MAP_WRITE,函数直接返回 NULL,GetLastError() 为 ERROR_ACCESS_DENIED。
-
CreateFile的dwShareMode建议设FILE_SHARE_READ,否则其他进程无法同时只读打开同一文件 - 映射大小由
CreateFileMapping的dwMaximumSizeHigh/dwMaximumSizeLow控制,不是MapViewOfFile的参数 -
UnmapViewOfFile后无需 CloseHandle 映射对象 —— 它可复用,但CloseHandle文件句柄仍是必须的
mmap 与 MapViewOfFile 的关键差异点
二者语义接近,但底层行为和容错逻辑不同。最易被忽略的是:Linux mmap 在 MAP_PRIVATE 模式下,即使文件后续被外部修改,已映射内容仍保持映射时刻的副本;而 Windows FILE_MAP_COPY 类似,但 FILE_MAP_READ 是实时视图 —— 若文件被截断或重写,再次访问对应页可能触发 EXCEPTION_IN_PAGE_ERROR(表现为崩溃或异常)。
- Linux
mmap支持MAP_POPULATE预加载页,减少首次访问缺页中断;Windows 无等价机制,需手动VirtualAlloc+ReadFile模拟 - 跨平台封装时,别假设“只读映射=绝对安全”——例如 Linux 上用
MAP_SHARED | PROT_READ映射可写文件,若另一进程修改该文件,你的只读视图会同步更新,但不会报错 - 64 位系统下,
mmap的addr参数建议传NULL让内核选择;WindowsMapViewOfFile的dwFileOffsetHigh/Low是从文件开头算起,不是从映射对象起始
大文件映射失败的三个高频原因
10 GB 以上文件映射失败,往往不是代码写错,而是环境或权限限制。比如 Linux 上 /proc/sys/vm/max_map_area 限制单进程 mmap 区域总数;Windows 上默认用户模式地址空间仅 2GB(32 位),即使文件只有 1GB,也可能因碎片无法找到连续虚拟内存块。
- Linux:检查
ulimit -v(虚拟内存)和cat /proc/sys/vm/max_map_count,必要时调高 - Windows:32 位程序务必启用
/LARGEADDRESSAWARE链接器选项,否则无法使用 >2GB 地址空间 - 两者都需确认文件是否被杀毒软件/备份工具独占锁定(Linux 表现为
ETXTBUSY,Windows 为ERROR_SHARING_VIOLATION)
映射本身很快,但首次访问某一页才真正加载数据 —— 如果你只读前几 MB 就退出,其实绝大部分磁盘 I/O 根本没发生。这点常被误判为“映射没生效”。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











