[Я повторю часть моего ответа отсюда .]
Почему бы просто не иметь команду, которая создает новый процесс с нуля? Разве не абсурдно и неэффективно копировать тот, который будет заменен сразу?
На самом деле это, вероятно, будет не так эффективно по нескольким причинам:
«Копия» производится fork()
немного абстракции, так как ядро использует копирования при записи системы ; все, что действительно нужно создать, это карта виртуальной памяти. Если копия немедленно вызывает exec()
, большая часть данных, которые были бы скопированы, если бы она была изменена в результате действия процесса, фактически никогда не должна копироваться / создаваться, потому что процесс не делает ничего, требующего его использования.
Различные важные аспекты дочернего процесса (например, его окружение) не должны дублироваться индивидуально или устанавливаться на основе сложного анализа контекста и т. Д. Они просто предполагаются такими же, как и у вызывающего процесса, и это довольно интуитивная система, с которой мы знакомы.
Чтобы объяснить # 1 немного дальше, память, которая «копируется», но к которой впоследствии не осуществляется доступ, никогда не копируется, по крайней мере, в большинстве случаев. Исключением в этом контексте может быть то, что если вы разветвили процесс, а потом родительский процесс завершил работу, прежде чем дочерний процесс заменил себя на exec()
. Я бы сказал, потому что большая часть родительского объекта может быть кэширована, если имеется достаточно свободной памяти, и я не уверен, в какой степени это будет использовано (что будет зависеть от реализации ОС).
Конечно, это не делает использование копии более эффективным, чем использование чистого листа - за исключением того, что «чистый лист» не является буквально ничем и должен включать распределение. Система может иметь общий пустой / новый шаблон процесса, который копируется таким же образом 1, но тогда это ничего не спасет по сравнению с форком копирования при записи. Итак, № 1 просто демонстрирует, что использование «нового» пустого процесса не будет более эффективным.
Пункт № 2 объясняет, почему использование вилки, вероятно, более эффективно. Окружение дочернего объекта наследуется от его родителя, даже если это совершенно другой исполняемый файл. Например, если родительский процесс представляет собой оболочку, а дочерний веб-браузер $HOME
все еще одинаков для них обоих, но, поскольку каждый из них может впоследствии изменить его, это должны быть две отдельные копии. Тот, что в ребенке, производится оригиналом fork()
.
1. Стратегия, которая может не иметь большого буквального смысла, но моя точка зрения заключается в том, что создание процесса подразумевает не только копирование его изображения в память с диска.