这是一种与子进程共享只读内存的安全方法吗?

时间:2010-02-09 19:53:46

标签: c linux shared-memory

我想分配并初始化相当大的连续内存块(~1GB),然后将其标记为只读并分叉多个(比如几十个)将使用它的子进程,而不会创建自己的副本内存(机器没有足够的内存)。

我是否正确地认为,如果我像往常一样malloc内存,然后使用mprotect(addr, size, PROT_READ)然后fork将其标记为只读,这将允许子进程安全使用内存而不会导致它被复制? (假设我确保在mprotect调用后没有尝试写入分配的内存。

编辑:感谢您的所有答案。

后续问题 - 我计划使用shmget,但我认为它使用mm,因此仅限于较小的分配(请参阅Restrictions section of this page)。例如/proc/sys/kernel/shmmax在服务器上是32MB我正在使用这个。但我想要1GB的连续内存。我错了这个限制吗?

6 个答案:

答案 0 :(得分:7)

man mprotect

  

实现将要求 addr sysconf()返回的页面大小的倍数。

     

如果未通过调用mmap()建立映射,则未指定此函数的行为。

  1. mprotect仅适用于页面,而不适用于任意字节范围,因此通常malloc不合适。 posix_memalign可能会有所帮助,但是......
  2. 虽然目前它可能适用于您的系统,但您应该 mprotect任何您自己mmap未提及的内容。请改用mmap(0, pages*sysconf(_SC_PAGESIZE), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0)

答案 1 :(得分:3)

由于任何子进程都可以调用mprotect()来删除保护并开始在那里写作,所以你不对。如果页面尚未复制,则会违反fork()

的原则

即使它的工作方式是将写时复制用于分叉进程,我也不认为 standards 中的任何地方都这样说(POSIX并没有说它是复制的) - 例如,写。)

您可以使用标准度量来共享内存,而不是使用非标准行为。例如,POSIX与shm_open和后续mmap共享内存(正如评论中指出的那样,postephemient解释)。文件描述符将通过分叉保存。

答案 2 :(得分:2)

没有必要将其标记为只读,只需让您的子进程单独使用即可。

如果父母和孩子都没有写信给它,它应该保持共享状态。如果你不想改变它,那很好。

如果你想写信,你会想要使用带有MAP_SHARED的mmap。

答案 3 :(得分:1)

您假设内核将执行 copy-on-write 优化,而不是复制mprotect页面。不过我会指望它。 malloc - 内存中包含各种各样的元数据 - 保护页面等等,只有Ulrich Drepper知道libc内部发生了什么:)

在磁盘文件中准备数据并将它们mmap放入所有进程中,或者只是转到正常的POSIX shm_open路径可能更容易,更安全。

答案 4 :(得分:0)

我的理解是肯定的,因为Linux对传递给子进程的内存页使用了写时复制机制。

答案 5 :(得分:0)

你可以这样做。

另一种方法是使用mmap()

另一种方法是使用POSIX共享内存(shm_open());另一个主要替代方案是System V共享内存(shmget()shmat())。正式共享内存系统的一个优点是您的父进程可以创建内存,然后无关的进程可以连接到它 - 如果这是有益的。