共享内存技术疑问:shm_open与open选型及msync使用时机
背景
当前我的应用有一个通过malloc分配的全局数组,几乎所有函数都会对其进行更新。应用还设有信号处理函数,收到信号时会将该数组内容写入磁盘文件。
示例代码
app.c
static int *list; void function_1() { list[0]++; } void function_2() { list[1]++; } void function_3() { list[2]++; } int main () { get_storage (&list, 4); signal(SIGINT, handle_sigint); list[3]++; function_1(); function_2(); function_3(); } void handle_sigint (int sig) { // Write the array List to file }
storage.c
void get_storage (int **list, int len) { int total_size = (len + 1) * sizeof(int); int *arr = (int *) malloc (total_size); memset (addr, 0, total_size); arr[0] = len; *list = (arr + 1); }
用例
我计划移除信号处理函数,改用共享内存/mmap分配数组(由文件作为后端存储),确保应用运行时文件始终保存数组的最新内容。
示例代码
app.c
static int *list; void function_1() { list[0]++; } void function_2() { list[1]++; } void function_3() { list[2]++; } int main () { get_storage (&list, 4); list[3]++; function_1(); function_2(); function_3(); }
storage.c
void get_storage (int **list, int len) { char shm_name [255] = {0}; snprintf (shm_name, 255, "list_%d_file.dat", (int)getpid()); int total_size = (len + 1) * sizeof(int); int shm_fd = shm_open (shm_name, O_CREAT | O_RDWR, 0666); ftruncate(shm_fd, total_size); void *addr = mmap(0, total_size, PROT_WRITE|PROT_READ, MAP_SHARED, shm_fd, 0); memset (addr, 0, total_size); int *arr = (int *)addr; arr[0] = len; *list = (arr + 1); }
问题
- 推荐使用
shm_open(在/dev/shm创建文件)还是open(可在任意目录创建文件)?/dev/shm空间有限且系统重启后数据不保留,两种方式的开销差异是什么? - 何时应使用
msync?是否需要在每次数组更新后调用?若需如此,那么malloc加信号处理器的方案似乎更优。我在实验中发现不调用msync数据也能实时更新,在Linux系统下不使用msync有什么影响?
回答
关于shm_open和open的选择与开销
- 选择依据:
- 如果数据不需要跨系统重启保留,且优先追求性能,选
shm_open更合适——/dev/shm是基于内存的tmpfs文件系统,所有读写操作都在内存中完成,只是套了文件系统的接口; - 如果需要数据持久化(系统重启后仍能保留),必须用
open在普通磁盘目录创建文件,因为/dev/shm的内容会随系统重启完全清空。
- 如果数据不需要跨系统重启保留,且优先追求性能,选
- 开销差异:
shm_open创建的文件完全驻留内存,读写没有磁盘IO开销,性能和匿名共享内存几乎无差别;open操作普通磁盘文件时,即便用了mmap,内核仍会异步将脏页刷到磁盘,虽然不会阻塞你的写操作,但后台存在磁盘IO开销,极端场景下可能影响整体性能。另外,磁盘文件的存储空间受磁盘容量限制,而/dev/shm的大小通常为系统内存的一半左右。
关于msync的使用场景与不调用的影响
- 何时使用
msync:
不需要每次更新都调用。msync的核心作用是强制将mmap区域的脏页刷入磁盘,确保数据持久化。一般在这些场景下调用:程序即将退出、完成一个关键操作阶段,或者需要让其他进程立刻看到磁盘上的最新数据时。 - 不调用
msync的影响:
Linux内核会自动异步刷脏页到磁盘(默认周期约30秒,可通过/proc/sys/vm/dirty_expire_centisecs等参数调整),你实验中看到数据实时更新,可能是刚好内核触发了自动刷页,或者写完后立刻读取磁盘文件时,内核为保证一致性主动完成了刷页。但不调用msync会存在以下风险:- 若程序意外崩溃,崩溃前未被内核刷盘的脏页数据会丢失;
- 其他进程直接读取磁盘文件时,可能看不到最新修改,需等到内核完成异步刷页;
- 如果用
shm_open对应tmpfs的文件,因为本身就在内存中,msync几乎没有作用,也无需调用——tmpfs的“刷盘”只是内存内的操作,不会写入物理磁盘。
内容的提问来源于stack exchange,提问作者MSK
相关产品推荐
相关产品推荐

