C++无跨平台内存映射API,需系统调用:Linux/macOS用mmap,Windows用CreateFileMapping+MapViewOfFile;仅映射目标字节所在页对齐区域(如4KB),修改后msync/FlushViewOfFile刷盘,munmap/UnmapViewOfFile释放。

用 mmap 修改大文件特定字节,不加载全部内容到内存
直接结论:C++ 本身没有跨平台内存映射 API,必须依赖系统调用——Linux/macOS 用 mmap,Windows 用 CreateFileMapping + MapViewOfFile。核心思路是只映射需要修改的页对齐区域(通常 4KB 对齐),而非整个文件。
常见错误是试图 mmap 整个几十 GB 的文件,结果进程因虚拟内存耗尽被 OOM killer 杀掉,或 mmap 返回 MAP_FAILED。正确做法是计算目标偏移所在的页边界,仅映射覆盖该偏移的一小段(比如 4KB~64KB),改完后 msync 刷盘、munmap 释放。
-
off_t offset = target_byte_pos & ~(sysconf(_SC_PAGESIZE) - 1);—— 向下对齐到页首 - 映射长度至少为
target_byte_pos - offset + 1(保证能写到目标字节) - 必须用
PROT_READ | PROT_WRITE和MAP_SHARED,否则修改不会落盘 - 注意
mmap的offset参数必须是页对齐值,否则失败
Linux 下 mmap 修改单字节的最小可行示例
假设要将文件 /tmp/big.bin 的第 12345678 字节改为 0xFF:
int fd = open("/tmp/big.bin", O_RDWR);
if (fd == -1) { /* handle error */ }
<p>off_t target = 12345678;
long page_size = sysconf(_SC_PAGESIZE); // 通常是 4096
off_t map_off = target & ~(page_size - 1);
size_t map_len = page_size; // 足够覆盖 target</p><p>uint8_t<em> addr = (uint8_t</em>)mmap(nullptr, map_len, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, map_off);
if (addr == MAP_FAILED) { /<em> handle error </em>/ }</p><p>addr[target - map_off] = 0xFF;</p><p><span>立即学习</span>“<a href="https://pan.quark.cn/s/6e7abc4abb9f" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">C++免费学习笔记(深入)</a>”;</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/gongju/2823" title="C++14"><img
src="https://img.php.cn/upload/manual/001/431/639/6ac8b33c327c4749.png" alt="C++14" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/gongju/2823" title="C++14">C++14</a>
<p>C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。</p>
</div>
<a href="/xiazai/gongju/2823" title="C++14" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div><p>msync(addr, map_len, MS_SYNC); // 确保写入磁盘
munmap(addr, map_len);
close(fd);</p>关键点:target - map_off 是映射区内的相对偏移,不是文件全局偏移;msync 不可省略,否则可能只在 page cache 中修改,断电即丢。
Windows 下等效操作需绕过 C++ 标准库限制
Windows 没有 mmap,但行为一致:用 CreateFile 打开文件(带 GENERIC_READ | GENERIC_WRITE),再用 CreateFileMapping 创建可写映射对象,最后 MapViewOfFile 获取指针。
- 映射起始位置也必须是 64KB 对齐(Windows 的“allocation granularity”,非页大小)
- 实际可读写范围仍由
MapViewOfFile的dwNumberOfBytesToMap和偏移共同决定 - 修改后调用
FlushViewOfFile(对应msync),再UnmapViewOfFile - C++ 标准库(如
std::fstream)完全不支持这种底层映射,必须用 Win32 API
容易忽略的陷阱和性能影响
最常踩的坑不是语法,而是语义误判:
- 文件必须存在且有写权限;
truncate或ftruncate扩容后再mmap,否则写越界会触发SIGBUS - 多个进程同时映射同一文件并写不同区域——安全;但写重叠区域时无自动同步,需额外加锁(如
flock) -
mmap映射的是虚拟地址,不立即分配物理内存;首次访问才发生 page fault,所以“映射快”不等于“数据已加载” - 频繁小范围映射/解映射开销不小(涉及内核态切换),若需多次修改,应复用同一映射段,而非每次重新
mmap
页对齐计算、映射长度控制、刷盘时机这三点,漏掉任一个都可能导致静默失败或数据损坏。尤其在服务端长期运行程序中,msync 被注释掉或写成 MS_ASYNC 是典型线上事故源头。


















