fork()上的手册页声明它不复制数据页,它将它们映射到子进程并放置写时复制标志。是这种行为:
我想知道我是否可以使用fork()作为一种廉价获取共享只读内存块的方法。如果内存是物理复制的,那将是相当昂贵的 - 有很多分叉正在进行,而且数据区域足够大 - 但我希望不会......
答案 0 :(得分:3)
在没有MMU(内存管理单元)的机器上运行的Linux将复制fork()上的所有进程内存。
然而,这些系统通常非常小并且是嵌入式的,您可能不必担心它们。
Apache的fork模型等许多服务使用initialize和fork()方法来共享初始化的数据结构。
您应该知道,如果您使用Perl和Python等使用引用计数变量或C ++ shared_ptr的语言,则此模型将不起作用。它不起作用,因为随着参考计数的上下调整,内存变得非共享并被复制。
这会导致像SpamAssassin这样的Perl守护进程中的大量内存使用尝试使用初始化和fork模型。
答案 1 :(得分:3)
是的,你肯定可以在MMU-Linux内核上依赖它;这几乎是一切。
然而,页面大小在各处都不一样。
通过使用mmap()创建一个匿名映射(一个不受物理文件支持的映射),可以显式为分叉进程创建一个共享内存区域。在fork上,此区域将始终保持共享(前提是子项不会将其取消映射,或者在同一地址中映射其他内容)。如果需要,您可以将其保护为只读。
使用(例如)malloc分配的内存很容易最终与一些不是只读的内容共享一个页面,这意味着当另一个结构被修改时它会被复制。这包括malloc实现使用的内部结构。因此,您可能希望为此目的mmap特定区域并从中进行分配。
答案 2 :(得分:2)
你能依靠所有Linux风格都这样做的事实吗?不。但你可以依赖那些不使用偶数更快的方法的人。
因此,如果遇到性能问题,您应该使用该功能并依赖它并重新审视您的决定。
答案 3 :(得分:2)
这种方法的成功取决于你坚持自我强加的“只读”限制。父母和孩子都必须遵守这种限制,否则就会复制内存。
然而,这可能不是你想象的灾难。内核可以复制一个页面(通常为4 KB)来实现CoW语义。典型的Linux服务器将使用更复杂的东西,某种slab allocator,因此复制的区域可能会大得多。
重点是,这与你的程序的内存使用概念分离。如果malloc()
1 GB的RAM,分叉子进程,并且子进程只更改该内存块的第一个字节,则不会复制整个1 GB的块。也许只有一页被复制,直到包含第一个字节的slab大小。
答案 4 :(得分:1)
所有的Linux发行版使用相同的内核,虽然版本和发行版略有不同。
另一个潜在的fork(2)实现不太可能在不久的将来更快,所以可以肯定的是,写时复制将继续成为机制。也许它不会永远,但多年来,绝对是。
当然,一些主要的软件系统(例如,Phusion Passenger)会以您想要的方式使用fork(2),因此您不会是唯一利用CoW的人。