Если вы fork() и разветвленный (дочерний) процесс завершается, все ли страницы VM по-прежнему помечены как COW в родительском?

В Linux, если вы fork() и разветвленный (дочерний) процесс завершается, все ли страницы виртуальной памяти по-прежнему помечены как копирование при записи в родительском?

Я думаю, что страницы останутся помеченными как COW, так как все остальное, вероятно, было бы непомерно дорогим в реализации, возможно, потребовало бы подсчета ссылок на страницу и другого дорогостоящего учета. Но на днях мне было интересно, если я разветвлю процесс для выполнения некоторого кода в «стабильном снимке» текущего процесса. Что происходит, когда дочерний процесс завершается? Все ли страницы памяти в родительском элементе остаются помеченными как копируемые при записи? Это означает, что разветвление процесса с большим объемом виртуальной памяти (например, 128 ГБ+) только для выполнения некоторого кода в течение нескольких минут приведет к длительному снижению производительности родительского процесса на несколько часов или даже дней (не говоря уже о самом вызове разветвления). что будет недешево)

Мне просто любопытно, каково реальное поведение в Linux (и я понятия не имею, как я могу это проверить).


person Eloff    schedule 23.03.2013    source источник
comment
Я не уверен, но вы должны использовать posix_spawn, а не fork, для запуска внешних программ.   -  person R.. GitHub STOP HELPING ICE    schedule 23.03.2013
comment
IIRC, COW устанавливается как на родительской, так и на дочерней страницах. Первый пришедший получает ошибку страницы, и страница клонируется (и ни на одной из клонированных страниц больше не установлен COW). Кстати: вы можете посмотреть на источник. Это с открытым исходным кодом, вы знаете...   -  person wildplasser    schedule 23.03.2013


Ответы (2)


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

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

Теперь, когда родитель записывает страницу с установленным битом COW и счетчиком ссылок, равным единице, бит COW просто игнорируется.

person jbr    schedule 23.03.2013

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

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

person teppic    schedule 23.03.2013