我想分配和初始化一个相当大的连续内存块(〜1GB),然后将其标记为只读并分叉多个(比如几十个)subprocess将使用它,而不使自己的内存副本机器将没有足够的内存这个)。
我正确的想,如果我malloc
内存像往常一样,然后将其标记为mprotect(addr, size, PROT_READ)
,然后fork
,这将允许subprocess安全地使用内存,而不会导致它复制? (提供我保证在mprotect
调用之后没有任何东西试图写入分配的内存)。
编辑:感谢所有的答案。
一个后续问题 – 我正在计划使用shmget
,但是我认为它使用了mm
,因此将被限制为较小的分配(参见本页的限制部分 )。 例如/proc/sys/kernel/shmmax
是我使用这个服务器上的32MB。 但是我想要1GB的连续内存。 我错了这个限制吗?
男人mprotect
实现将要求addr是sysconf()返回的页面大小的倍数。
如果映射不是通过调用mmap()来建立的,则此函数的行为是未指定的。
mprotect
只能在页面上工作,而不是任意的字节范围,所以一般malloc
是不合适的。 posix_memalign
可能有帮助,但… mprotect
你自己没有的东西。 改用mmap(0, pages*sysconf(_SC_PAGESIZE), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0)
。 由于这个原因,任何子进程都可以调用mprotect()
来删除保护并开始在那里写。 如果页面没有被复制,将违反fork()
的原则。
即使这样写入时拷贝被用于分叉进程,我也不会认为标准中有这样的地方(例如,POSIX并没有说它是copy-on-write)。
您可以使用标准的措施来共享内存,而不是使用非标准的行为。 例如,POSIX共享内存与shm_open
和随之而来的mmap
(正如在评论中指出的,并在ephemient的解释中)。 文件描述符将通过分叉来保存。
无需将其标记为只读,只需让您的子进程保持独立。
如果父母和孩子都不写信,它应该保持共享。 如果你不想改变它,那很好。
如果要写入,则需要使用带有MAP_SHARED的mmap。
你假设内核将进行写时拷贝优化,而不是复制mprotect
页面。 我不会指望它。 malloc
-ed内存中有各种各样的元数据 – 保护页面等等,只有Ulrich Drepper知道在libc里面发生了什么:)
在磁盘文件中准备数据并将它们mmap
到所有进程或者使用正常的POSIX shm_open
路径可能会更容易,更安全。
我的理解是肯定的,因为Linux使用传递给子进程的内存页面的写入时复制机制。
你可以这样做。
另一种方法是使用mmap() 。
另一种方法是使用POSIX共享内存( shm_open() ); 另一个主要的选择是System V共享内存( shmget() , shmat() )。 正式的共享内存系统的一个优点是你的父进程可以创建内存,然后不相关的进程可以连接到它 – 如果这是有益的。