use*_*186 3 linux memory fork copy-on-write
我已经阅读了关于在 Linux 中分叉新进程时发生的写时复制原则。
我还了解到,如果一个程序的多个实例同时运行,则只能在内存中找到该程序代码的一个实例。
我想知道这是否是写时复制原则的直接后果,如果不是,确保程序代码的不必要副本不会驻留在内存中的过程是什么?
我想知道这是否是写时复制原则的直接结果
不,这不对。FWIW,您可以在没有 COW 的情况下共享代码段,也可以在没有共享代码段的情况下拥有 COW。它是独立的。
如果通过 COW 实现共享程序代码,那么只有相关进程才能从中受益。
例如,如果进程Afork 两次并创建进程Band C,然后B并在同一个二进制文件上C调用七个exec函数之一,那么您可以说代码段是由于 COW 共享的 - 因为代码段在执行期间从未被写入,并且映射为只读,那么它必须自动共享,对吗?
如果从另一个 shell 启动相同的可执行文件怎么办?(或者其他一些不相关的进程派生并执行相同的程序?它不必是一个外壳......)
如果代码段共享是 COW 的结果,在这种情况下,我们不会从共享代码段中受益,因为这些进程是不相关的(因此开始时没有与其他实例共享 COW 的页面)。
相反,代码段与内存映射文件共享。在内存中加载新的可执行文件时,mmap(2)调用将二进制文件的内容映射到内存中。
如果不是,那么确保程序代码的不必要副本不会驻留在内存中的过程是什么?
确切的实现细节取决于操作系统,但并没有那么复杂。从概念上讲,mmap(2)将文件映射到内存中,因此您只需要在底层文件表示上保持一些状态,以跟踪该文件的哪些(如果有)内存映射是活动的。此类信息通常保存在文件的inode 中。
Linux为例,与内存地址空间相关联的文件i_mapping的领域struct inode。因此,当mmap(2)第一次调用二进制文件时,会分配物理内存页来保存信息并i_mapping设置该文件的 inode 字段;稍后的调用将使用该i_mapping字段并意识到有一个与此 inode 相关联的地址空间,并且由于它是只读的,因此没有分配物理页面,因此所有内容最终都被共享。请注意,每个进程中的虚拟内存可能不同,尽管它引用相同的物理页面(这意味着内核至少会分配和更新每个进程的页表,但仅此而已)。
该inode结构定义在fs.h- 我只能猜测其他 UNIX 变体以类似的方式执行此操作。
当然,只要使用相同的二进制文件,这一切都有效。如果复制二进制文件并分别执行两个副本,由于显而易见的原因,代码段将不会共享。