一个fork()系统调用克隆会从正在运行的进程子进程。这两个进程除了它们的 PID 之外是相同的。
当然,如果进程只是从它们的堆中读取而不是写入,那么复制堆将是对内存的巨大浪费。
整个进程堆是否被复制?它是否以仅写入触发堆复制的方式进行了优化?
mmk*_*mmk 29
Linux 内核在fork()被调用时确实实现了写时复制。执行系统调用时,父子进程共享的页面被标记为只读。
如果在只读页面上执行写操作,则会复制该页面,因为两个进程之间的内存不再相同。因此,如果只执行读取操作,则根本不会复制页面。
qdo*_*dot 23
在整体的fork()使用mmap实现/写时复制。
这不仅会影响堆,还会影响共享库、堆栈、BSS 区域。
顺便说一句,这意味着 fork 是一个非常轻量级的操作,直到产生的 2 个进程(父进程和子进程)真正开始写入内存范围。此功能是造成 fork-bombs 致命性的主要因素 - 在内核因页面复制和分化而过载之前,您最终会遇到太多进程。
您将很难在现代操作系统中找到内核执行硬拷贝(设备驱动程序除外)的操作示例 - 使用 VM 功能要容易得多,效率也高得多。
Evenexecve()本质上是“请映射二进制文件/ld.so/whatnot,然后执行”-VM 处理将进程实际加载到 RAM 和执行的过程。本地未初始化的变量最终从“零页”- 包含零的特殊只读写时复制页面被映射,本地初始化变量最终从二进制文件本身被映射(再次写时复制),等等。
unx*_*nut 12
Linux 执行写时复制。当fork创建一个新进程时,分配的页面被标记为只读并在父子进程之间共享。当它们中的任何一个尝试修改页面时,都会生成页面错误,从而导致复制页面并适当调整页表。