Как работает COW после форка?

Я читал об использовании COW-подхода после выполнения fork в современных UNIX-подобных системах.

Предположим, у нас есть процесс — P1. Он разветвляется; получаем еще один процесс — P2. Их виртуальная память поддерживается теми же физическими страницами из-за COW. Существует страница, на которой расположена одна статическая глобальная переменная (например, static long variable; вне main) (в сегменте .data), поддерживаемая физической страницей A.

Теперь P1 изменяет свою статическую глобальную переменную; ядро после обработки сбоя защиты отображает новую страницу (страницу B) в виртуальную память P1 для хранения этой измененной переменной.

Точно так же, как P2 изменяет свою статическую глобальную переменную, ядро ​​после обработки сбоя защиты отображает новую страницу (страницу C) в виртуальную память P1 для хранения этой измененной переменной.

Теперь ничто не ссылается на страницу А. Где она находится? Я полагаю, это не «висит в воздухе», удерживая одну физическую страницу неиспользуемой, тем самым тратя память?


person Bulat M.    schedule 28.09.2016    source источник
comment
Почему бы тогда просто не изменить A, поскольку на него ссылается только один? И зачем его хранить в физической памяти, если его никто не использует?   -  person Sami Kuhmonen    schedule 28.09.2016
comment
@ Сами, вы имеете в виду, что P2 мог просто изменить флаги A'pages вместо сопоставления новой C-страницы? Я думаю, что у родителя может быть несколько детей, поэтому A должен оставаться доступным только для чтения?   -  person Bulat M.    schedule 28.09.2016


Ответы (2)


Когда страница B создается, флаг COW на странице A удаляется, потому что страница больше не является общедоступной; больше нет необходимости копировать его перед изменением. Следовательно, P2 просто использует страницу A, возможно, вообще не вызывая ошибки страницы и, конечно же, без необходимости копировать страницу. Следовательно, страницы C нет, и страница A не остается без ссылок.

Обратите внимание, что если P1 разветвляется снова, или если P2 разветвляется, или и то, и другое, перед изменением переменной на странице A, тогда может быть 3 или более процессов, ссылающихся на страницу. Система обычно поддерживает счетчик ссылок для каждой страницы в информации управления отображением памяти, записывая, сколько процессов имеют страницу, отображаемую в их памяти процессов, и этот счетчик определяет, может ли быть очищен флаг COW. Пока на страницу ссылается только один процесс, флаг COW остается в силе.

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

person Jonathan Leffler    schedule 28.09.2016

Страница A не становится висящей, потому что имеет место только одна копия.

Один из двух процессов сначала вызовет COW. Он получит новый кадр B, а другой процесс останется с A.

Мы могли бы сделать так, чтобы другой процесс не сталкивался с ошибкой страницы. Это, вероятно, чревато гонками, особенно при использовании SMP, когда каждое ядро ​​​​имеет свой собственный TLB.

Или мы можем позволить другому процессу также получить ошибку страницы. Он будет знать, что кадр A больше не требует копирования, потому что, скажем, в объекте управления есть счетчик ссылок, который отслеживает A, и этот счетчик ссылок имеет значение 1, указывающее, что A однозначно отображается. Таким образом, обработчик ошибки страницы просто пометит страницу как существующую, сохраняя ее сопоставленной с A.

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

person Kaz    schedule 28.09.2016
comment
Что произойдет, если процесс быстро порождает несколько дочерних процессов? У нас есть счетчик ссылок где-то в ядре, который уменьшается на единицу, если какой-либо дочерний элемент записывает на страницу (таким образом вызывая ошибку защиты и получая новую страницу)? - person Bulat M.; 28.09.2016
comment
@БулатМ. Это может работать так. В какой-то момент мы должны знать, что этой страницы больше ни у кого нет, и она может остаться. - person Kaz; 28.09.2016