fork() 是否会立即复制 Linux 中的整个进程堆?

Ada*_*tan 33 linux fork

一个fork()系统调用克隆会从正在运行的进程子进程。这两个进程除了它们的 PID 之外是相同的。

当然,如果进程只是从它们的堆中读取而不是写入,那么复制堆将是对内存的巨大浪费。

整个进程堆是否被复制?它是否以仅写入触发堆复制的方式进行了优化?

mmk*_*mmk 29

Linux 内核在fork()被调用时确实实现了写时复制。执行系统调用时,父子进程共享的页面被标记为只读。

如果在只读页面上执行写操作,则会复制该页面,因为两个进程之间的内存不再相同。因此,如果只执行读取操作,则根本不会复制页面。

  • 2. - 在页面中 :) 内核对什么是“堆”知之甚少 - 对于内核来说,它只是一堆 mmapped 私有页面,libc 分配器可以随意处理。 (4认同)

qdo*_*dot 23

整体fork()使用mmap实现/写时复制。

这不仅会影响堆,还会影响共享库、堆栈、BSS 区域。

顺便说一句,这意味着 fork 是一个非常轻量级的操作,直到产生的 2 个进程(父进程和子进程)真正开始写入内存范围。此功能是造成 fork-bombs 致命性的主要因素 - 在内核因页面复制和分化而过载之前,您最终会遇到太多进程。

您将很难在现代操作系统中找到内核执行硬拷贝(设备驱动程序除外)的操作示例 - 使用 VM 功能要容易得多,效率也高得多。

Evenexecve()本质上是“请映射二进制文件/ld.so/whatnot,然后执行”-VM 处理将进程实际加载到 RAM 和执行的过程。本地未初始化的变量最终从“零页”- 包含零的特殊只读写时复制页面被映射,本地初始化变量最终从二进制文件本身被映射(再次写时复制),等等。


unx*_*nut 12

Linux 执行写时复制。当fork创建一个新进程时,分配的页面被标记为只读并在父子进程之间共享。当它们中的任何一个尝试修改页面时,都会生成页面错误,从而导致复制页面并适当调整页表。