Копируется ли вся память, помеченная как copy-on-write, после одного изменения в один фрагмент данных?


Мой вопрос, возможно, плохо сформулирован и проистекает из моего дилетантского понимания управления памятью.

Меня беспокоит вот что: у меня есть сценарий Perl, который разветвляется много раз. Как я понял из страницы fork в perldoc, реализуется функция копирования при записи. Затем каждый из детей вызывает system(), снова разветвляясь, чтобы вызвать внешнюю программу. Данные из внешней программы считываются обратно в дочерний файл и сбрасываются в виде сохраняемого файла, который будет собран и обработан родителем. как только все дети вышли.

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

Но, с другой стороны, копирует ли программа copy-on-write только самый маленький фрагмент памяти, содержащий необходимые данные? Затем что это за кванты памяти? Как устанавливается его размер?

Я не уверен, зависит ли специфика того, о чем я спрашиваю, от языка или от какого-то процесса более низкого уровня.
2 4

2 ответа:

Память организована в виде страниц, обычно 4K каждая (это может быть установлено в различные значения и зависит от аппаратного обеспечения, но это норма на платформах Intel со стандартными операционными системами). Когда дочерний процесс выполняет запись на страницу копирования при записи, он будет скопирован.

Да, раздвоение увеличит объем вашей памяти. Если это проблема, используйте модуль типа Parallel::ProcManager или Forks::Super это может уменьшить количество активных фоновых процессов. Ограничение числа активных вилок также полезно, когда ваши процессы связаны с ЦП, вводом-выводом или могут чрезмерно использовать любой другой ограниченный ресурс на вашей машине.

use Forks::Super MAX_PROC => 10, ON_BUSY => block;

...
$pid = fork();        # blocks if there are already 10 child processes
...                   # unblocks when one of the children finishes