Когда процесс разветвляется, копируется ли его виртуальная или резидентная память?

12

Стандартный способ создания новых процессов в Linux состоит в том, что объем памяти родительского процесса копируется, и он становится средой дочернего процесса до тех пор, пока не execvбудет вызван.

О каком объеме памяти мы говорим, виртуальном (о чем просил процесс) или резидентном (что на самом деле используется)?

Мотивация: у меня есть устройство с ограниченным пространством подкачки и приложение с большой разницей между виртуальной и резидентной памятью. Приложение не может быть разветвлено из-за нехватки памяти и хочет посмотреть, поможет ли попытка уменьшить размер виртуальной зоны.

TheMeaningfulEngineer
источник

Ответы:

12

В современных системах ни одна память фактически не копируется только потому, что используется системный вызов fork. В таблице страниц все помечено только для чтения, что при первой попытке записать ловушку в код ядра произойдет. Копирование произойдет только после первой попытки процесса записи.

Это известно как копирование при записи.

Однако может потребоваться также отслеживать зафиксированное адресное пространство. Если в то время, когда ядру нужно скопировать страницу, памяти или подкачки нет, то для освобождения памяти необходимо убить какой-то процесс. Это не всегда желательно, поэтому можно отслеживать, сколько памяти выделено ядром.

Если ядро ​​выполнит фиксацию больше чем доступная память + подкачка, оно может выдать код ошибки при попытке вызвать fork. Если доступно достаточно, ядро ​​передаст полный виртуальный размер родительского для обоих процессов после разветвления.

kasperd
источник
1
If enough is available the kernel will commit to the full virtual size of the parent for both processes after the fork.Да спасибо. Это означает, что уменьшение виртуального следа процесса в среде с ограниченной памятью (ОЗУ и подкачка) может решить проблему невозможности форка.
TheMeaningfulEngineer
1
@ Алан Да. Если происходит forkсбой с сообщением об ошибке, указывающим на недостаток памяти. Тогда может помочь уменьшение использования виртуальной памяти процессом перед разветвлением.
kasperd
5

Не волнуйтесь, это делает ленивую копию (копирование при записи). Адреса виртуальной памяти обоих процессов изначально указывают на одни и те же страницы, но когда разветвленный процесс пытается изменить его, он фактически создает физическую копию страницы (с тех пор эта страница находится в двух местах в вашей ОЗУ).

Помните, что ни один из зарегистрированных следов памяти на самом деле не говорит вам, сколько оперативной памяти использует процесс. Из-за перестановки, совместного использования памяти и других проблем с виртуальной памятью невозможно знать наверняка. Некоторые части пространства памяти являются общими библиотеками (где их считать?), Некоторые ссылаются на не-RAM память (другие аппаратные устройства), некоторые в настоящее время выгружены, некоторые еще не скопированы (копирование при записи) и скоро. Прочитайте это:

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

Орион
источник
5

Есть настройки ядра

/ 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, форк будет копироваться при записи. Копирование при записи означает, что после того, как приложение разветвится, обе его копии будут совместно использовать страницы памяти, если дочерний элемент или оригинал начнет изменять память.

В большинстве дистрибутивов я знаю, что overcommit равен 0. Но если вы установите его на 2, все страницы памяти будут полностью защищены реальной памятью, а в некоторых случаях под высоким давлением памяти будут более стабильными, но некоторые программы (я сталкивался с gitk), которые полагаются на сверхкоммитах не получится.

gena2x
источник