Распределение памяти дочерних процессов и цель получения дочерних процессов - PullRequest
0 голосов
/ 14 ноября 2018

Я новичок в процессах, все еще пытаюсь понять цель сбора дочерних процессов и выделения памяти для них, поэтому мои вопросы:

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

Q2. В моих учебниках говорится, что когда пользователи используют fork () для создания нового дочернего процесса, дочерний элемент получает идентичную (но отдельную) копию родительского текста, данных, сегментов bss, кучи и пользовательского стека. Значит ли это, что тот же размер адреса памяти родителей выделяется и ребенку, и содержание памяти ребенка точно так же, как и его родитель? если так, скажем, мы создаем огромное количество дочерних процессов, разве стек не будет очень легко переполняться?

Q3. Допустим, картинка ниже является родительским процессом enter image description here

и вы можете видеть, что стек пользователя, выделенный красным цветом, является стеком родителя. Итак, если родительская программа использует fork () и когда она выполняет функцию fork (), как выделяется стек дочерних процессов? дочерний стек рядом с текущим стеком

Ответы [ 2 ]

0 голосов
/ 14 ноября 2018

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

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

Каждый процесс имеет свое собственное адресное пространство.Это реализовано с использованием виртуальной памяти ;сопоставление виртуальных адресов с реальными доступами к оборудованию, которое для всех целей и задач невидимо для процесса пользовательского пространства.(Виртуальная память не является адресной, но использует небольшие блоки, называемые pages . На всех современных архитектурах каждая страница имеет размер двух байтов. 2 12 = 4096 обычно, но также используются другие размеры, такие как 2 16 = 65536 и 2 21 = 2097152.)

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

Когда процесс выполняется с помощью fork (), виртуальная память клонируется.(На самом деле это не скопированное само по себе, так как это приведет к потере ресурсов. Обычно ядро ​​ОС использует метод copy-on-write , так что фактическая физическая память ОЗУиспользуется для памяти, используемой обоими / всеми процессами, до тех пор, пока один из них не изменит свою «копию», после чего ядро ​​ОС отсоединяет уязвимую страницу, дублируя ее содержимое, прежде чем продолжить изменение.)

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

Единственное ограничение - это объем доступной оперативной памяти.На самом деле ядро ​​ОС также может перемещать неиспользуемые в настоящее время файлы в файл подкачки или файл подкачки ;но если эти страницы скоро понадобятся, это замедляет работу машины.В Linux, по крайней мере, двоичные файлы и библиотеки также напрямую сопоставляются с их соответствующими файлами - по этой причине вы не можете изменять исполняемые файлы, когда они используются, поэтому, если копия кода в ОЗУ не изменена, оникак правило, не используют файл подкачки / подкачки.

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

Интересная деталь в Linux состоит в том, что, как правило, стек по умолчаниюразмер для новых потоков довольно большой, 8 МБ (8 388 608 байт) на 32-разрядной x86.Если вы не установите меньший стек, число потоков, которые может создать процесс, ограничено доступной виртуальной памятью.Каждый процесс в пользовательском пространстве может использовать младшие 3 ГБ или адреса виртуальной памяти ниже 3221 225 472 на 32-разрядной платформе x86;и вы можете разместить в нем не более 384 стеков по 8 МБ.Если вы учитываете стандартные библиотеки и т. Д., Обычно в этих системах процесс может создать около 300 потоков, прежде чем он исчерпает виртуальную память.Если вы используете намного меньший стек, скажем, 65536 байт, процесс может создать тысячи потоков даже на 32-битной x86.Просто помните, что проблема заключается в нехватке доступного адресного пространства виртуальной памяти , а не памяти как таковой.

0 голосов
/ 14 ноября 2018

Q1. Почему в Linux нет механизма автоматического получения дочерних процессов, я имею в виду, что все дочерние процессы завершаются и удаляются после завершения, как сборка мусора, так что пользователям не нужно использовать waitpid для ручного сбора дочерних процессов?

Это так. Просто настройте игнорирование SIGCHLD, и ваши дети будут пожинать вам деньги.

Q2. В моих учебниках говорится, что когда пользователи используют fork () для создания нового дочернего процесса, дочерний элемент получает идентичную (но отдельную) копию родительского текста, данных, сегментов bss, кучи и пользовательского стека. Значит ли это, что тот же размер адреса памяти родителей выделяется и ребенку, и содержание памяти ребенка точно такое же, как и у его родителя?

Это деталь реализации. Большинство современных систем просто разделяют память между двумя процессами.

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

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

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

Стек дочернего процесса находится в другом процессе. Так что, если это адресное пространство для сегментов родительского процесса, стек дочернего процесса в нем вообще отсутствует. Дочерний процесс начинается с копии адресного пространства родителя - обычно с фактическими общими страницами памяти, по крайней мере, до тех пор, пока какой-либо процесс не попытается изменить их (что делает их общими). ​​

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...