多进程场景下通过mremap调整POSIX共享内存大小的疑问
答案:进程2必须执行相关操作
好问题!这是共享内存使用中很容易踩的坑——进程1的扩容操作只对它自己的地址空间生效,进程2如果不做处理,根本没法正常使用扩容后的共享内存。具体原因和操作步骤如下:
核心原因:每个进程的内存映射是独立的
共享内存的物理区域是多进程共用的,但每个进程通过mmap()建立的虚拟地址到物理内存的映射是完全独立的:
ftruncate()只是修改了共享内存对象的物理大小,但不会自动更新其他进程的映射范围。进程2的映射还是原来的长度,一旦访问超出原长度的区域,会直接触发SIGSEGV段错误,因为这些虚拟地址没有绑定到有效的物理内存。- 进程1调用的
mremap()(带MREMAP_MAYMOVE)仅调整了它自己进程内的虚拟地址映射,对进程2的地址空间没有任何影响。进程2的旧映射既不会自动扩大,也不会跟着移动(如果进程1的映射被移到新虚拟地址的话)。
进程2需要执行的操作
借助你们已有的进程同步机制(确保进程1完成扩容后再执行),进程2需要做以下步骤:
- 确认共享内存的新大小:通过
fstat()获取共享内存文件描述符的st_size字段,拿到扩容后的尺寸。 - 更新自己的内存映射:
- 方式一(推荐,更高效):调用
mremap(),传入旧的映射地址、旧长度、新长度,加上MREMAP_MAYMOVE参数,直接调整映射的范围。 - 方式二(更稳妥,兼容性好):先调用
munmap()解除旧的映射,再重新用mmap()映射整个扩容后的共享内存段(注意用MAP_SHARED参数)。
- 方式一(推荐,更高效):调用
额外注意事项
- 必须严格遵循同步机制:一定要等进程1完成
ftruncate()和mremap()后,进程2再执行映射更新,否则可能出现映射大小与实际共享内存大小不匹配的问题。 - 如果进程1的
mremap()只是扩容没有移动地址,进程2的mremap()大概率也能在原地址上扩大映射;但如果进程1的映射被移动了,进程2的旧地址就失效了,必须重新映射或者用mremap()调整。
内容的提问来源于stack exchange,提问作者Ody
相关产品推荐
相关产品推荐

