当进程分叉时,其虚拟内存或常驻内存是否会被复制?

当进程分叉时,其虚拟内存或常驻内存是否会被复制?

在 Linux 中创建新进程的标准方法是复制父进程的内存占用并成为子进程的环境,直到execv被调用。

我们正在谈论什么内存占用,虚拟内存(进程请求的内存)还是驻留内存(实际正在使用的内存)?

动机:我有一个交换空间有限的设备和一个虚拟内存占用和驻留内存占用之间有很大差异的应用程序。由于内存不足,应用程序无法分叉,并且希望了解尝试减小虚拟占用空间大小是否有帮助。

答案1

在现代系统中,实际上并没有因为使用了 fork 系统调用而复制任何内存。它在页表中全部标记为只读,因此第一次尝试将陷阱写入内核代码时就会发生。只有当第一个进程尝试写入时才会发生复制。

这称为写入时复制。

然而,可能还需要跟踪提交的地址空间。如果内核必须复制页面时没有可用的内存或交换区,则它必须终止某些进程以释放内存。这并不总是可取的,因此可以跟踪内核已提交的内存量。

如果内核提交的内存超过可用内存+交换空间,它可能会在尝试调用 fork 时给出错误代码。如果有足够的可用空间,内核将在分叉后为两个进程提交父进程的完整虚拟大小。

答案2

别担心,它会进行惰性复制(写时复制)。两个进程的虚拟内存地址最初都指向相同的页面,但是当分叉进程尝试修改它时,它实际上会创建该页面的物理副本(从那时起,该页面驻留在 RAM 中的两个位置)。

请注意,所报告的内存占用实际上并没有告诉您该进程使用了​​多少 RAM。由于虚拟内存的交换、内存共享和其他问题,不可能确定。内存空间的某些部分是共享库(在哪里计算它们?),一些引用非 RAM 内存(其他硬件设备),一些当前已换出,一些尚未复制(写时复制)和很快。读这个:

https://lwn.net/Articles/642202/

答案3

有内核设置

/proc/sys/vm/overcommit_memory

优秀引文文章:

Since 2.5.30 the values are: 0 (default): as before: guess about how much  
overcommitment is reasonable, 1: never refuse any malloc(), 2: be precise 
about the overcommit - never commit a virtual address space larger than swap 
space plus a fraction overcommit_ratio of the physical memory. Here 
/proc/sys/vm/overcommit_ratio (by default 50) is another user-settable 
parameter. It is possible to set overcommit_ratio to values larger than 100. 
(See also Documentation/vm/overcommit-accounting.)

这适用于分叉以及常规 malloc。即,如果将其设置为 0,fork 将在写入时复制。写入时复制意味着一旦应用程序分叉,它的两个副本将共享内存页面,直到子级或原始版本开始更改内存。

在大多数发行版中,我知道过度使用是0。但是如果将其设置为2,所有内存页面将完全由真实内存支持,并且在某些情况下在高内存压力下会更稳定,但是某些程序(我遇到过gitk)依赖于过度使用将会失败。

相关内容