如何将MAP_PRIVATE内存映射文件的修改写回磁盘?
关于MAP_PRIVATE内存映射修改写回磁盘的问题
当使用MAP_PRIVATE标志做文件内存映射时,写入操作产生的修改只会保留在内存中,不会同步回磁盘。根据msync(3)的手册说明:
对MAP_PRIVATE映射调用msync()函数时,任何修改的数据都不会写入底层对象,也不会让其他进程可见这些数据
核心问题
是否存在将MAP_PRIVATE映射的修改写回磁盘的方法?
典型应用场景
- 使用
MAP_PRIVATE映射文件 - 仅在内存中做修改(速度快),同时保留磁盘上的原始版本(安全)
- 在特定时机(用户确认、验证更改一致性后)将修改写入磁盘
当前实现方案
int fd = open("aaa",O_RDWR); void* p = mmap ( NULL , n , PROT_READ | PROT_WRITE , MAP_PRIVATE | MAP_NORESERVE , fd , 0 ); // ... // 向p写入数据;更改仅存在于内存中 // ... // 现在使用MAP_SHARED进行映射 void* p2= mmap ( NULL , n , PROT_READ | PROT_WRITE , MAP_SHARED | MAP_NORESERVE , fd , 0 ); memcpy(p2,p,n); // 将所有数据从p复制到p2 msync(p2,n); // 解除映射/重新映射p,为新更改做准备 munmap(p,n); p = mmap ( NULL , n , PROT_READ | PROT_WRITE , MAP_PRIVATE | MAP_NORESERVE , fd , 0 );
当前实现的疑问与问题
- 需要复制全部内容,无法仅同步修改的部分
- 这段代码是否合法?两种映射之间是否存在潜在冲突,导致未定义行为?
解答
代码合法性说明
这段代码完全合法,Linux内核允许同一文件描述符同时存在MAP_PRIVATE和MAP_SHARED两种映射,二者不会产生未定义行为。内核会对两种映射的内存页做严格区分:MAP_PRIVATE的脏页是进程专属的副本,MAP_SHARED的页直接关联磁盘文件。你执行的memcpy只是把私有副本的内容复制到共享映射的内存区域,再通过msync同步到磁盘,整个流程是安全可靠的。
优化:仅同步修改部分
要避免全量复制,核心是追踪MAP_PRIVATE映射中被修改的页面,只同步这些脏页:
- 信号追踪法:初始时用
mprotect把映射页面设为只读,当进程尝试写入时会触发SIGSEGV信号,在信号处理函数中记录被修改的页面地址,再将该页面权限改为可写。 - 用户态位图标记:维护一个与映射页面对应的位图,每次写入内存时标记对应页面为脏。
- 同步时,仅将标记为脏的页面内容复制到
MAP_SHARED映射的对应位置,再调用msync同步这些特定区域即可。
替代方案
如果脏页追踪的实现成本过高,也可以直接使用MAP_SHARED映射,但在修改前先创建文件快照或备份。这种方案既能利用共享映射的同步特性,又能在需要时恢复原始版本,但额外开销可能比脏页追踪更大,需根据场景选择。
内容的提问来源于stack exchange,提问作者PierU
相关产品推荐
相关产品推荐

