You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

共享内存技术疑问: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);

}
问题
  1. 推荐使用shm_open(在/dev/shm创建文件)还是open(可在任意目录创建文件)?/dev/shm空间有限且系统重启后数据不保留,两种方式的开销差异是什么?
  2. 何时应使用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会存在以下风险:
    1. 若程序意外崩溃,崩溃前未被内核刷盘的脏页数据会丢失;
    2. 其他进程直接读取磁盘文件时,可能看不到最新修改,需等到内核完成异步刷页;
    3. 如果用shm_open对应tmpfs的文件,因为本身就在内存中,msync几乎没有作用,也无需调用——tmpfs的“刷盘”只是内存内的操作,不会写入物理磁盘。

内容的提问来源于stack exchange,提问作者MSK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 16:26:08