Добавлен: 29.10.2018
Просмотров: 48058
Скачиваний: 190
216
Глава 3. Управление памятью
Рис. 3.1. Три простых способа организации памяти при наличии операционной системы и одного
пользовательского процесса (существуют и другие варианты). При таком устройстве системы
памяти процессы, как правило, могут запускаться только по одному. Как только пользователь на-
берет команду, операционная система копирует запрошенную программу с диска в память, после
чего выполняет эту программу. Когда процесс завершает свою работу, операционная система
отображает символ приглашения и ожидает ввода новой команды. По получении команды она
загружает в память новую программу, записывая ее поверх первой программы
программу. Поскольку одновременно в памяти присутствует только одна программа,
конфликтов не возникает. Эта концепция называется заменой данных (или свопингом)
и будет рассмотрена чуть позже.
При наличии некоторого специального дополнительного оборудования появляется
возможность параллельного запуска нескольких программ даже без использования
свопинга. На ранних моделях IBM 360 эта проблема решалась следующим образом:
память делилась на блоки по 2 Кбайт, каждому из которых присваивался 4-битный
защитный ключ, содержащийся в специальных регистрах за пределами центрального
процессора. Машине с объемом памяти 1 Мбайт нужно было иметь лишь 512 таких
4-битных регистров, и все хранилище ключей занимало в итоге 256 байт памяти. Сло-
во состояния программы (Program Status Word (PSW)) также содержало 4-битный
ключ. Аппаратное обеспечение IBM 360 перехватывало любую попытку запущенного
процесса получить доступ к памяти с ключом защиты, отличающимся от ключа PSW.
Поскольку изменить ключи защиты могла только операционная система, пользова-
тельские процессы были защищены от вмешательства в работу друг друга и в работу
самой операционной системы.
Тем не менее это решение имело серьезный недостаток, показанный на рис. 3.2. Здесь
изображены две программы, каждая из которых имеет объем 16 Кбайт. Они показа-
ны на рис. 3.2, а и б. Первая из них закрашена, чтобы показать, что у нее иной ключ
памяти, нежели у второй. Первая программа начинается с перехода на ячейку памяти
с адресом 24, в которой содержится команда MOV. Вторая программа начинается с пере-
хода на ячейку памяти с адресом 28, в которой содержится команда CMP. Команды,
не имеющие отношения к рассматриваемому вопросу, на рисунке не показаны. Когда
две программы загружаются друг за другом в память, начиная с ячейки с адресом 0,
мы получаем ситуацию, показанную на рис. 3.2, в. В этом примере мы предполагаем,
что операционная система находится в верхних адресах памяти и поэтому не показана.
3.1. Память без использования абстракций
217
Рис. 3.2. Иллюстрация проблемы перемещения: а — программа объемом 16 Кбайт;
б — еще одна программа объемом 16 Кбайт; в — две программы, последовательно
загруженные в память
После загрузки программы могут быть запущены на выполнение. Поскольку у них
разные ключи памяти, ни одна из них не может навредить другой. Но проблема имеет
иную природу. При запуске первой программы будет выполнена команда JMP 24 и, как
и ожидалось, осуществлен переход к другой команде. Эта программа будет успешно
работать.
Но после того как первая программа проработает достаточно долго, операционная си-
стема может принять решение на запуск второй программы, которая была загружена
над первой программой, начиная с адреса 16 384. Первой исполняемой командой будет
JMP 28, осуществляющая переход к команде ADD первой программы вместо того, чтобы
перейти к предполагаемой команде CMP. Скорее всего, это приведет к сбою программы
на первой же секунде.
В данном случае суть проблемы состоит в том, что обе программы ссылаются на абсо-
лютный адрес физической памяти, что совершенно не соответствует нашим желаниям.
Нам нужно, чтобы каждая программа ссылалась на занимаемый ею набор адресов.
Давайте вкратце рассмотрим, как это достигается. На IBM 360, например, в процессе
загрузки буквально на лету осуществлялась модификация второй программы, при этом
использовалась технология, известная как статическое перемещение. Она работала
следующим образом: когда программа загружалась с адреса 16 384, в процессе загрузки
к каждому адресу в программе прибавлялось постоянное значение 16 384 (следова-
тельно, инструкция «JMP 28» становилась инструкцией «JMP 16412» и т. д.). При
всей исправности работы этого механизма он был не самым универсальным решением,
и к тому же замедлял загрузку. Более того, это решение требовало дополнительной
информации обо всех исполняемых программах, сообщающей, в каких словах содер-
218
Глава 3. Управление памятью
жатся, а в каких не содержатся перемещаемые адреса. В результате чего 28 на рис. 3.2, б
должно было подвергнуться перемещению, а инструкция вроде
MOV REGISTER1,28
которая помещает число 28 в REGISTER1, должна была остаться нетронутой. Нужен
был какой-нибудь способ, позволяющий сообщить загрузчику, какое из чисел относит-
ся к адресу, а какое — к константе.
И наконец, как отмечалось в главе 1, в компьютерном мире истории свойственно
повторяться. Хотя прямая адресация физической памяти, к сожалению, осталась
в прошлом, в устаревших устройствах памяти универсальных компьютеров, мини-
компьютеров, настольных компьютеров, ноутбуков и смартфонов дефицит абстракций
памяти — вполне обычное явление во встроенных системах и смарт-картах. В наши дни
устройства вроде радиоприемников, стиральных машин и микроволновых печей за-
полнены программным обеспечением (в ПЗУ), и в большинстве случаев их программы
используют адресацию к абсолютной памяти. Все это неплохо работает, поскольку все
программы известны заранее, и пользователи не могут запускать на бытовых устрой-
ствах какие-нибудь собственные программы.
Сложные операционные системы присутствуют только в высокотехнологичных встро-
енных устройствах (например, в смартфонах), а более простые устройства их не име-
ют. В некоторых случаях у них тоже есть операционная система, но это всего лишь
библиотека, связанная с прикладной программой, которая предоставляет системные
вызовы для выполнения операций ввода-вывода и других общих задач. Простым при-
мером популярной операционной системы, представляющей собой библиотеку, может
послужить e-cos.
3.2. Абстракция памяти: адресные пространства
В конечном счете предоставление физической памяти процессам имеет ряд серьез-
ных недостатков. Во-первых, если пользовательские программы будут обращаться
к каждому байту памяти, они легко могут преднамеренно или случайно испортить
операционную систему, раздробить ее код и довести до остановки работы (в отсутствие
специального аппаратного обеспечения наподобие ключевых схем и блокировок на
IBM 360). Эта проблема присутствует даже при запуске всего лишь одной пользова-
тельской программы (приложения). Во-вторых, при использовании этой модели до-
вольно сложно организовать одновременную (поочередную, если имеется лишь один
центральный процессор) работу нескольких программ. На персональных компьютерах
вполне естественно наличие нескольких одновременно открытых программ (текстовый
процессор, программа электронной почты, веб-браузер), с одной из которых в данный
момент взаимодействует пользователь, а работа других возобновляется щелчком мыши.
Так как этого трудно достичь при отсутствии абстракций на основе физической памяти,
нужно что-то предпринимать.
3.2.1. Понятие адресного пространства
Чтобы допустить одновременное размещение в памяти нескольких приложений без
создания взаимных помех, нужно решить две проблемы, относящиеся к защите и пере-
мещению. Примитивное решение первой из этих проблем мы уже рассматривали на
3.2. Абстракция памяти: адресные пространства
219
примере IBM 360: участки памяти помечались защитным ключом, и ключ выполняе-
мого процесса сличался с ключом каждого выбранного слова памяти. Этот подход не
решал второй проблемы, хотя она могла быть решена путем перемещения программ
в процессе их загрузки, но это было слишком медленным и сложным решением.
Более подходящее решение — придумать для памяти новую абстракцию: адресное
пространство. Так же как понятие процесса создает своеобразный абстрактный цен-
тральный процессор для запуска программ, понятие адресного пространства создает
своеобразную абстрактную память, в которой существуют программы. Адресное
пространство
— это набор адресов, который может быть использован процессом для
обращения к памяти. У каждого процесса имеется собственное адресное пространство,
независимое от того адресного пространства, которое принадлежит другим процессам
(за исключением тех особых обстоятельств, при которых процессам требуется совмест-
ное использование их адресных пространств).
Понятие адресного пространства имеет весьма универсальный характер и появляет-
ся во множестве контекстов. Возьмем телефонные номера. В США и многих других
странах местный телефонный номер состоит обычно из семизначного числа. Поэтому
адресное пространство телефонных номеров простирается от 0000000 до 9999999, хотя
некоторые номера, к примеру те, что начинаются с 000, не используются. С ростом
количества смартфонов, модемов и факсов это пространство стало слишком тесным,
а в этом случае необходимо использовать больше цифр. Адресное пространство портов
ввода-вывода процессора x86 простирается от 0 до 16 383. Протокол IPv4 обращается
к 32-разрядным номерам, поэтому его адресное пространство простирается от 0 до
2
32
− 1 (опять-таки с некоторым количеством зарезервированных номеров).
Адресное пространство не обязательно должно быть числовым. Набор интернет-доме-
нов
.com
также является адресным пространством. Это адресное пространство состоит
из всех строк длиной от 2 до 63 символов, которые могут быть составлены из букв,
цифр и дефисов, за которыми следует название домена —
.com
. Теперь вам должна
стать понятной сама идея, в которой нет ничего сложного.
Немного сложнее понять, как каждой программе можно выделить собственное адресное
пространство, поскольку адрес 28 в одной программе означает иное физическое место,
чем адрес 28 в другой программе. Далее мы рассмотрим простой способ, который ранее
был распространен, но вышел из употребления с появлением возможностей размеще-
ния на современных центральных процессорах более сложных (и более совершенных)
схем.
Базовый и ограничительный регистры
В простом решении используется весьма примитивная версия динамического пере-
распределения памяти
. При этом адресное пространство каждого процесса просто
проецируется на различные части физической памяти. Классическое решение, при-
мененное на машинах от CDC 6600 (первого в мире суперкомпьютера) до Intel 8088
(сердца первой модели IBM PC), заключается в оснащении каждого центрального
процессора двумя специальными аппаратными регистрами, которые обычно называ-
ются базовым и ограничительным регистрами. При использовании этих регистров
программы загружаются в последовательно расположенные свободные области памяти
без модификации адресов в процессе загрузки (см. рис. 3.2, в). При запуске процесса
в базовый регистр загружается физический адрес, с которого начинается размещение
220
Глава 3. Управление памятью
программы в памяти, а в ограничительный регистр загружается длина программы. На
рис. 3.2, в при запуске первой программы базовыми и ограничительными значениями,
загружаемыми в эти аппаратные регистры, будут соответственно 0 и 16 384. При за-
пуске второй программы будут использованы значения 16 384 и 32 768 соответствен-
но. Если непосредственно над второй будет загружена и запущена третья программа,
имеющая объем 16 Кбайт, значениями базового и ограничительного регистров будут
32 768 и 16 384 соответственно.
При каждой ссылке процесса на память с целью извлечения команды или записи сло-
ва данных аппаратура центрального процессора перед выставлением адреса на шине
памяти добавляет к адресу, сгенерированному процессом, значение базового регистра.
Одновременно аппаратура проверяет, не равен ли предлагаемый адрес значению огра-
ничительного регистра или не превышает ли он это значение (в этом случае генериру-
ется отказ и доступ прерывается). Если взять первую команду второй программы (см.
рис. 3.2, в), то процесс выполняет команду
JMP 28
но аппаратура рассматривает ее как команду
JMP 16412
поэтому переход осуществляется, как и ожидалось, на команду CMP. Значения базо-
вых и ограничительных регистров при выполнении второй программы на рис. 3.2, в
показаны на рис. 3.3.
Рис. 3.3. Для предоставления каждому процессу отдельного адресного пространства
могут использоваться базовый и ограничительный регистры
Использование базового и ограничительного регистров — это простой способ предостав-
ления каждому процессу собственного закрытого адресного пространства, поскольку