8

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

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

编辑:感谢所有的答案。

一个后续问题 - 我计划使用shmget,但我认为它已使用mm,因此仅限于较小的分配(请参阅本页的限制部分)。例如/proc/sys/kernel/shmmax,在我使用这个的服务器上是 32MB。但我想要 1GB 的连续内存。我对这个限制有误吗?

4

6 回答 6

8

男人保护

该实现将要求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)
于 2010-02-09T20:07:53.313 回答
3

由于任何子进程都可以调用mprotect()以删除保护并开始在那里写入,因此您是不对的。如果页面没有被复制,那将违反fork().

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

您可以使用标准措施来共享内存,而不是使用非标准行为。例如,POSIX 与shm_open和随之而来的共享内存mmap(正如评论中指出的那样,并在他的帖子中由ehemient解释)。文件描述符将通过分叉保留。

于 2010-02-09T20:08:51.500 回答
2

无需将其标记为只读,只需让您的子进程不要管它。

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

如果您想写入它,您需要使用带有 MAP_SHARED 的 mmap。

于 2010-02-09T23:40:55.077 回答
1

您假设内核将执行时复制优化而不复制mprotect-ed 页面。我不会指望它。malloc-ed 内存有各种各样的元数据漂浮在它周围 - 保护页面等等等,只有 Ulrich Drepper 知道 libc 内部发生了什么:)

在磁盘文件中准备数据并将mmap其放入所有进程中可能会更容易和更安全,或者只是走正常的 POSIXshm_open路线。

于 2010-02-09T20:09:01.107 回答
0

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

于 2010-02-09T20:01:44.060 回答
0

你可以那样做。

另一种方法是使用mmap()

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

于 2010-02-09T20:10:44.023 回答