Является ли последовательность unix fork exec столь же дорогой, как кажется?

Я читаю о fork и exec для экзамена, и в моей книге говорится, что всякий раз, когда это необходимо для запуска нового (другого) процесса в Unix-системах, вы должны разветвлять текущий процесс, за которым следует execve.

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

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

Ответ 1

Обычно вилка фактически не копирует всю память, а использует "copy on write", что означает, что пока память не изменяется, используются одни и те же страницы. Однако, чтобы избежать нехватки памяти позже (если процесс записывается в память), необходимо выделить достаточное количество памяти.

Это означает, что при использовании большого процесса в системах, которые не позволяют переубеждать память, память должна быть доступна. Таким образом, если у вас есть процесс разворота на 8 ГБ, то в течение хотя бы короткого периода времени должно быть доступно 16 ГБ.

См. также vfork и posix_spawn для других решений.

Ответ 2

Некоторые системы, которые являются либо очень старыми (ранний Unix), либо очень специальными (mmu-linux) или очень дрянными (Windows через Cygwin), должны делать полную копию всех страниц ("каждый байт") на fork, поэтому потенциал есть.

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

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

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

Чтобы привести некоторые реальные цифры, в моей системе GNU/Linux я могу разветвляться + выходить 1340 раз в секунду из 20 МБ процесса, но только из 235 раз/с в 2000 МБ процессе. В обоих случаях это быстрее, чем vfork + execve, что несколько не интуитивно понятно, потому что многие думают, что "форк быстр" и "execve должен быть медленным".

Ответ 3

Нет копии памяти, если только один из процессов не изменил память, и в этом случае страница будет скопирована, и если вы вызываете exec() в дочернем процессе сразу после вызова fork(), копия не создается.

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

Я думаю, вы можете найти это в Advanced Programming в UNIX