一个fork()
系统调用克隆会从正在运行的进程子进程。除了PID以外,这两个过程是相同的。
自然地,如果进程只是从其堆中读取而不是对其进行写入,则复制堆将浪费大量内存。
是否复制了整个进程堆?是否以仅写入触发堆复制的方式进行了优化?
一个fork()
系统调用克隆会从正在运行的进程子进程。除了PID以外,这两个过程是相同的。
自然地,如果进程只是从其堆中读取而不是对其进行写入,则复制堆将浪费大量内存。
是否复制了整个进程堆?是否以仅写入触发堆复制的方式进行了优化?
Answers:
在整体的fork()
使用mmap实现/写时复制。
这不仅影响堆,还影响共享库,堆栈,BSS区域。
顺便说一句,这意味着fork是一个非常轻量级的操作,直到结果2个进程(父进程和子进程)实际开始写入内存范围为止。此功能是造成fork-bomb杀伤力的主要因素-在内核因页面复制和差异而超载之前,最终会导致太多进程。
您将很难在现代OS中找到内核执行硬拷贝(设备驱动程序除外)的操作示例-使用VM功能远非如此,容易得多且效率更高。
甚至execve()
本质上是“请在二进制文件上映射ld.so / whatnot,然后执行”-虚拟机将处理实际加载到RAM的进程并执行。局部未初始化变量最终从“零页”映射-特殊的只读只读复制页包含零,局部初始化变量最终从二进制文件本身被映射(再次写时复制),等等
fork()
调用时,Linux内核确实实现了写时复制。执行系统调用时,父级和子级共享的页面被标记为只读。
如果在只读页面上执行写操作,则将其复制,因为两个进程之间的内存不再相同。因此,如果仅执行读取操作,则将根本不会复制页面。
fork()
调用后的下一条指令开始执行。
/proc/self/pagemap
为测试目的确定虚拟地址到物理页面的映射。如我所料,如果孙子和只有孙子写共享页面,则父级和原始子级将继续共享它。只有孙子才能得到私人副本。