mmap写入默认不生效是因为prot未设PROT_WRITE且flags未用MAP_SHARED;需ftruncate预分配、页对齐msync、避免频繁同步以保性能。

为什么 mmap 写入模式默认不生效?
直接用 open() + mmap() 默认是只读映射,哪怕文件以 O_RDWR 打开,若没显式指定 PROT_WRITE 和 MAP_SHARED,写内存会触发 SIGSEGV。这不是权限问题,是映射属性没配对。
-
prot参数必须包含PROT_WRITE,否则内核禁止写入映射区域 -
flags必须用MAP_SHARED(不能用MAP_PRIVATE),否则修改不会落盘,且msync()无效 - 文件需提前
ftruncate()到目标大小,否则映射越界访问会崩(不是报错,是段错误)
如何安全地高频更新映射区而不卡顿?
高频写入时最常踩的坑是反复 msync() —— 它会阻塞直到脏页刷到磁盘,吞吐直接掉量级。真正高效的做法是让内核自动调度回写,只在必要节点干预。
- 写入前确保文件已用
ftruncate(fd, size)预分配,避免mmap()后再扩容(会破坏映射) - 避免每写一次就调
msync();改用MS_ASYNC异步刷,或干脆不调——Linux 默认 30 秒内会自动回写 - 若需强一致性(如断电不丢数据),在关键点用
msync(addr, len, MS_SYNC),但要控制频次,比如每 10 万次更新刷一次 - 注意
addr和len必须按页对齐(getpagesize()),否则msync()返回EINVAL
mmap 写入比 write() 快在哪?又有哪些隐藏成本?
快的本质是绕过内核缓冲区拷贝:用户态指针直接写入 page cache,省掉一次 copy_to_user。但代价是页表管理开销和 TLB 压力。
- 小量随机写( 拷贝成本
- 映射大文件(>1GB)时,
mmap()初始化本身有延迟,建议用MADV_RANDOM或MADV_WILLNEED提示内核 - 多线程并发写同一映射区需自行加锁(如
std::atomic_flag或pthread_mutex_t),mmap不提供原子性保障 - 进程退出前务必
munmap(),否则残留映射可能拖慢后续启动(尤其容器环境)
一个最小可运行的高频写入 mmap 示例
以下代码实现 10MB 文件的循环覆盖写入,每写 4KB 触发一次异步刷盘,无阻塞等待:
int fd = open("data.bin", O_RDWR | O_CREAT, 0644);
ftruncate(fd, 10 * 1024 * 1024);
size_t page_size = getpagesize();
void* addr = mmap(nullptr, 10 * 1024 * 1024, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
// 假设用 int32_t 类型写入
int32_t* data = static_cast<int32_t>(addr);
for (int i = 0; i <p>注意 <code>msync()</code> 的地址必须页对齐,上面用 <code>(i / 256) * page_size</code> 是为保证每次刷的是完整物理页——漏掉这点,高频下容易因部分页未刷导致数据不一致。</p></int32_t>
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











