Главная страница  Межпроцессное взаимодействие (состязание) 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 [ 128 ] 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

Предел верхней памяти


MINIX


Потомок А

MINIX

MINIX

Рис. 4.30. Выделение памяти: а - исходное состояние; б - после вызова fork; в - дочерний процесс сделал вызов exec. Неиспользованные области памяти отмечены штриховкой. У процесса код и данные находятся в одном адресном пространстве

Когда память распределяется по вызову fork или exec, некоторое ее количество отдается новому процессу. В первом случае запросы дочернего и родительского процессов удовлетворяются в равной мере. Во втором - менеджер памяти оперирует значением из заголовка исполняемого файла. После того как память была раз выделена, ни при каких условиях процесс не сможет посягнуть на дополнительную.

Сказанное выше относится к программам, которые были скомпилированы с объединенными адресными пространствами кода и данных. Программы, у которых эти пространства разделены, пользуются улучшенным вариантом управления памятью, который называется разделяемым кодом (shared text). Когда подобный процесс делает fork, память выделяется только под стек и данные дочернего процесса. Потомок получает в наследство исполняемый код, который используется родительским процессом. Когда делается exec, в таблице процессов ищется процесс, уже использующий требуемый код. Если такой процесс обнаруживается, память, опять же, выделяется только для данных и стека. Но совместное использование кода усложняет завершение процесса. При завершении процесса всегда освобождается память, занимаемая его данными и стеком. Память же, занимаемая сегментом текста, освобождается только и только тогда, если поиск в таблице процессов показал, что ни один другой процесс этот код больше не интересует. Может получиться так, что процессу при запуске выделяется больше памяти, чем освобождается при его завершении. Мы говорим про случай, если при запуске он загрузил собственный текст, а по окончании оказалось, что этот текст уже используется другими процессами.

На рис. 4.31 показано, как программа хранится в виде файла на диске и как она располагается в памяти, когда MINIX запускает процесс. Информация о размерах различных частей образа процесса находится в заголовке файла, так же как и сведения о его полном размере. Для программы с объединенными адресными пространствами кода и данных в заголовке указывается суммарный размер двух частей, они копируются напрямую в образ в памяти. Для сегмента данных образа при копировании в память выделяется больший объем. Размер дополни-



тельной области памяти в байтах хранится в поле bss заголовка. Эта область заполняется нулями и используется для неинициализированных статических данных. Общий объем памяти, который будет выделен процессу, задается полем заголовка total. Если, например, у программы код имеет длину 4 Кбайт, данные плюс bss занимают 2 Кбайт, и 1 Кбайт стек, а в заголовке указано выделить всего 40 Кбайт, то неиспользуемый промежуток памяти между сегментами данных и стека будет иметь размер 33 Кбайт. Кроме того, программа на диске может содержать таблицу символов. Она требуется для отладки и не загружается в память.

Размер файла на диске

Символы

Данные

Заголовок

Всего занято памяти

Стек


Данные - - bbs

Сегмент стека , растет вниз

Сегмент данных растет вверх (или вниз), когда делается системный вызов BRK

Рис. 4.31. 8 - программа хранится на диске в виде файла; б - внутреннее распределение памяти для одного процесса. На обеих частях рисунка в нижней части расположены

нижние адреса

Если программист знает, что общий объем памяти, необходимый для стека и данных программы в файле a.out, не превыщает 10 Кбайт, то при помощи команды

chmem = 10240 a.out

он может изменить поле заголовка исполняемого файла, после чего вызов exec будет выделять только 10 240 байт дополнительной памяти. Так, для описанного выще примера будет выделено 16 Кбайт памяти. Из этой памяти верхний килобайт будет отведен под стек, а 9 Кбайт образуют свободную область для будущего роста стека и/или области данных.

Для программ с раздельными адресными пространствами кода и данных (у которых компоновщик устанавливает специальный бит в заголовке программы), поле общего размера в заголовке относится только к стеку и данным. Так, при загрузке программы с 4 Кбайт кода, 2 Кбайт данных, 1 Кбайт стека и суммарным размером 64 Кбайт будет выделено 68 Кбайт памяти (4 Кбайт на код и 64 Кбайт образуют адресное пространство данных, а 61 Кбайт останется для роста стека и данных). Граница сегмента данных может быть изменена только при помощи системного вызова Ьгк. При выполнении этого вызова проверяется, не упирается ли новая граница сегмента данных в нижнюю границу стека, и соответствующие изменения вносятся во внутренние таблицы. Это делается исключительно на уровне менеджера памяти, так как у системы не запращивается никаких новых блоков памяти. Если же после изменения границы сегмент данных будет пересекаться со стеком, вызов завершается ошибкой.



Подобная стратегия была выбрана для того, чтобы MINIX могла работать на IBM PC с процессором 8086, который не делает аппаратной проверки переполнения стека. Пользовательская профамма может поместить в стек сколь угодно много слов, не ставя об этом в известность операционную систему. На системах с более сложным механизмом управления памятью под стек сначала выделяется некоторый объем памяти. Если делается попытка превысить квоту, генерируется прерывание и система, если это возможно, выделяет под стек дополнительное пространство. У процессоров 8086 такой механизм отсутствует, поэтому в их компании опасно оставлять стек соседствовать с чем-либо помимо большого блока незадействуемой памяти, так как стек может расти быстро и без предупреждения. MINIX написана так, чтобы при реализации на компьютере с улучшенным управлением памятью менеджер памяти было бы легко заменить.

Тут нужно упомянуть небольшую семантическую сложность. Когда мы говорим сегмент , мы имеем в виду область памяти, определяемую операционной системой. Но у процессоров Intel 80x86 есть специальные внутренние сегментные регистры и (у более новых из них) таблицы дескрипторов сегментов , обеспе-чиваюшие аппаратную поддержку сегментов . Концепция сегмента в аппаратной архитектуре Intel сходна с тем, как сегменты определяются в MINIX, но это не одно и то же. Все ссылки на сегменты в этом тексте следует рассматривать в контексте их определения в MINIX. Когда мы будем говорить об аппаратных сегментах, мы будем явно упоминать сегментные регистры и дескрипторы сегментов.

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

4.7.2. Обработка сообщений

Как и все остальные компоненты ОС MINIX, менеджер памяти управляется сообщениями. После инициализации системы менеджер памяти входит в свой главный цикл, в котором сообщение принимается, выполняется содержащийся в сообщении запрос и отправляется ответное сообщение. Допустимые типы сообщений, их параметры и отправляемые в ответ значения перечислены в табл. 4.3.

Вызовы fork, exit, wait, waitpid, Ьгк и exec тесно связаны с выделением и освобождением памяти. Вызовы kill, alarm и pause связаны с сигналами, такими как SIGALARM, SIGSUSPEND, SIGPENDING, SIGMARK и SIGRETURN. Они оказывают влияние и на память, так как при завершении процесса по сигналу занимаемая этим процессом память высвобождается. Вызов reboot воздействует на всю операционную систему, но прежде всего он отправляет сигналы, чтобы корректно завершить все



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 [ 128 ] 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

© 2000 - 2018 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования.