Файл: Debian Таненбаум Бос.pdf

ВУЗ: Не указан

Категория: Книга

Дисциплина: Операционные системы

Добавлен: 29.10.2018

Просмотров: 48084

Скачиваний: 190

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

266  

 Глава 3. Управление памятью 

процесс может получить собственную частную копию страниц с данными или же они 
могут совместно использоваться и иметь пометку «Только для чтения». Если какой-
нибудь процесс изменяет страницу данных, для него будет создана частная копия, то 
есть будет использована копия, пригодная для записи.

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

Вместо этого должна использоваться общая технология совместно используемых 
(общихбиблиотек, которые в Windows называются динамически подключаемыми 
библиотеками (Dynamic Link Libraries (DLL)). Чтобы сделать идею совместно исполь-
зуемой библиотеки более понятной, рассмотрим сначала традиционную компоновку. 
При компоновке программы в команде компоновщику указывается один или несколько 
объектных файлов и, возможно, несколько библиотек, как, например, в команде UNIX

ld *.o –lc –lm

которая компонует все файлы с расширением 

.o

 (object), имеющиеся в текущем 

каталоге, а затем сканирует две библиотеки, 

/usr/lib/libc.a

 и 

/usr/lib/libm.a

. Любые 

функции, вызываемые в объектных файлах, но не присутствующие в них (напри-
мер, printf), называются неопределенными внешними функциями и выискивают-
ся в библиотеках. Если они найдены, то их включают в исполняемый двоичный 
файл. Любые вызываемые, но не присутствующие в них функции также становятся 
неопределенными внешними функциями. К примеру, функции printf требуется 
функция write, поэтому, если функция write еще не включена, компоновщик будет 
ее разыскивать и, как только найдет, включит в двоичный файл. Когда компоновка 
завершится, исполняемый двоичный файл, записываемый на диск, будет содержать 
все необходимые функции. Имеющиеся в библиотеке, но невостребованные функции 
в него не включаются. Когда программа загружается в память и выполняется, в ней 
содержатся все необходимые ей функции.

Теперь предположим, что обычная программа использует 20–50 Мбайт функций, от-
носящихся к графике и пользовательскому интерфейсу. Статически скомпонованные 
сотни программ со всеми этими библиотеками будут тратить впустую громадный объем 
дискового пространства, а также пространства оперативной памяти, как только они 
будут загружены, поскольку у системы не будет способа узнать о том, что она может 
использовать эти библиотеки как общие. И тут на сцену выходят совместно используе-
мые библиотеки. Когда программа скомпонована с учетом совместного использования 
библиотек (что несколько отличается от статической компоновки), вместо включения 
реально вызываемых функций компоновщик включает небольшую подпрограмму-за-
глушку, которая в процессе исполнения привязывается к вызываемой функции. В за-
висимости от системы или от особенностей конфигурации совместно используемые 
библиотеки загружаются либо при загрузке программы, либо когда присутствующие 
в них функции вызываются в первый раз. Разумеется, если совместно используемая 
библиотека уже загружена другой программой, то нет нужды загружать ее повторно — 
именно в этом и заключается весь смысл. Следует заметить, что при загрузке или ис-
пользовании общей библиотеки вся библиотека разом в память не считывается. Она 
загружается постранично, по мере надобности, поэтому функции, которые не были 
вызваны, в оперативную память не переносятся.


background image

3.5. Разработка систем страничной организации памяти   

267

Сделать исполняемые файлы меньшими по объему и сэкономить пространство памяти 
помогает еще одно преимущество совместно используемых библиотек: если функция, 
находящаяся в общей библиотеке, обновляется с целью устранения ошибки, то пере-
компилировать программу, которая ее вызывает, не нужно. Старые двоичные файлы 
сохраняют свою работоспособность. Это свойство приобретает особое значение для 
коммерческого программного обеспечения, код которого не доставляется клиенту. 
Например, если корпорация Microsoft находит и исправляет ошибку, влияющую на 
безопасность системы в некой стандартной библиотеке DLL, программа обновле-
ния — Windows Update — загрузит новую DLL и заменит ею старую библиотеку, и все 
программы, использующие данную DLL, будут при следующем запуске автоматически 
использовать новую версию.

Но совместно используемые библиотеки пришли к нам с одной небольшой пробле-
мой, требующей решения. Эта проблема показана на рис. 3.24. Здесь отображены два 
процесса, совместно использующие библиотеку размером 20 Кбайт (предположим, 
что каждый ее блок занимает 4 Кбайт). Но библиотека в каждом процессе располага-
ется по разным адресам, по-видимому, потому что сами программы не совпадают по 
размеру. В процессе 1 библиотека размещается, начиная с адреса 36 К; в процессе 2 
ее размещение начинается с адреса 12 К. Предположим, первое, что должна сделать 
первая функция библиотеки, — перейти в библиотеке к адресу 16. Если библиотека не 
использовалась совместно, она может быть перемещена на лету в процессе загрузки, по-
этому переход (в процессе 1) может быть осуществлен на виртуальный адрес 36 К + 16. 
Следует заметить, что физический адрес оперативной памяти, по которому размеща-
ется библиотека, не имеет значения, пока все страницы отображаются с виртуальных 
на физические адреса аппаратурой диспетчера памяти — MMU.

Но как только библиотека начинает использоваться совместно, перемещение на 
лету уже работать не будет. В конце концов, когда первая функция вызывается

Рис. 3.24. Общая библиотека, используемая двумя процессами

процессом 2 (по адресу 12 К), команда перехода вынуждена осуществить его на адрес 
12 К + 16, а не на адрес 36 К + 16. В этом и заключается небольшая проблема. Одним из 
путей ее решения является использование копии при записи и создании новых страниц 
для каждого процесса, использующего общую библиотеку, и перемещение их на лету 
во время создания. Но эта схема, разумеется, дискредитирует всю цель совместного 
использования библиотеки.


background image

268  

 Глава 3. Управление памятью 

Лучшее решение заключается в компиляции совместно используемых библиотек со 
специальным флажком для компилятора, указывающим этому компилятору не соз-
давать никаких команд, использующих абсолютную адресацию. Вместо этого приме-
няются лишь те команды, которые используют относительную адресацию. Например, 
почти всегда есть команда, предписывающая переход вперед (или назад) на n байтов 
(в качестве альтернативы той команде, которая дает для перехода конкретный адрес). 
Эта команда работает правильно независимо от размещения совместно используемой 
библиотеки в виртуальном адресном пространстве. Проблема может быть решена за 
счет исключения абсолютной адресации. Код, использующий только относительные 
смещения, называется позиционно независимым кодом.

3.5.7. Отображаемые файлы

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

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

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

3.5.8. Политика очистки страниц

Замещение страниц лучше всего работает при наличии достаточного количества сво-
бодных страничных блоков, которые могут потребоваться при возникновении ошибки 
отсутствия страницы. Если заполнен и, более того, изменен каждый страничный блок, 
то перед помещением в него новой страницы сначала должна быть записана на диск 
старая страница. Для обеспечения поставки свободных страничных блоков системы 
замещения страниц, как правило, имеют фоновый процесс, называемый страничным 
демоном

, который большую часть времени находится в состоянии спячки, но перио-

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


background image

3.5. Разработка систем страничной организации памяти   

269

используя какой-нибудь алгоритм замещения страниц. Если эти страницы со времени 
своей загрузки подверглись изменению, они записываются на диск.

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

Один из способов реализации этой политики очистки предусматривает использование 
часов с двумя стрелками. Передняя стрелка управляется страничным демоном. Когда 
она указывает на измененную страницу, эта страница сбрасывается на диск и передняя 
стрелка перемещается вперед. Когда она указывает на чистую страницу, то происходит 
только перемещение вперед. Задняя стрелка используется для замещения страниц, как 
в стандартном алгоритме «часы». Только теперь благодаря работе страничного демона 
повышается вероятность того, что задняя стрелка попадет на чистую страницу.

3.5.9. Интерфейс виртуальной памяти

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

Одним из поводов предоставления программистам контроля над отображением памя-
ти является разрешение одному или нескольким процессам совместно использовать 
одну и ту же память, иногда весьма сложными способами. Если программисты могут 
присваивать имена областям памяти, то появляется возможность одному процессу 
предоставить другому процессу имя области памяти, чтобы этот процесс мог также 
отображаться на нее. Когда два (или несколько) процесса совместно используют одни 
и те же страницы, появляется возможность использования общего высокоскоростного 
канала: один процесс ведет запись в общую память, а другой процесс считывает из нее 
данные. Сложный пример такого коммуникационного канала описан Де Брюйном 
(De Bruijn, 2011).

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

Еще одна передовая технология управления памятью называется распределенной па-
мятью совместного доступа

 (Feeley et al., 1995; Li, 1986; Li and Hudak, 1989; Zekauskas 


background image

270  

 Глава 3. Управление памятью 

et al., 1994). В ее основе лежит идея, заключающаяся в том, чтобы позволить несколь-
ким процессам через сетевое подключение совместно использовать набор страниц, при 
этом возможно, но не обязательно, в качестве единого общего линейного диапазона 
адресов. Когда процесс обращается к странице, которая в данный момент не имеет 
отображения, у него происходит ошибка отсутствия страницы. Затем обработчик этой 
ошибки, который может быть в ядре или в пользовательском пространстве, определяет 
машину, содержащую эту страницу, и посылает ей сообщение с просьбой отключить 
отображение страницы и переслать ее по сети. По прибытии страницы она отобража-
ется, и команда, вызвавшая ошибку, перезапускается. Более подробно распределенная 
память совместного доступа будет рассмотрена в главе 8.

3.6. Проблемы реализации

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

3.6.1. Участие операционной системы в процессе 
подкачки страниц

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

При создании нового процесса в системе со страничной организацией памяти опера-
ционная система должна определить, каким будет (первоначально) объем программы 
и данных, и создать для них таблицу страниц. Для таблицы страниц нужно выделить 
пространство в памяти, а затем ее нужно инициализировать. При выгрузке процесса 
таблица страниц не должна быть резидентной, но она должна находиться в памяти 
при запуске процесса. Кроме того, в области подкачки на диске должно быть выде-
лено пространство, чтобы при выгрузке страницы ее было куда поместить. Область 
подкачки также должна быть инициализирована, туда должны быть помещены текст 
программы и данные, чтобы после запуска нового процесса в случае возникновения 
ошибки отсутствия страницы оттуда могли быть извлечены недостающие страницы. 
Некоторые системы подкачивают текст программы непосредственно из исполняе-
мого файла, экономя дисковое пространство и время на инициализацию. И наконец, 
информация о таблице страниц и области подкачки на диске должна быть записана 
в таблице процесса.

Когда процесс планируется на выполнение, диспетчер памяти (MMU) должен быть 
перезапущен под новый процесс, а содержимое буфера быстрого преобразования адреса 
(TLB) должно быть очищено, чтобы избавиться от следов ранее выполнявшегося про-
цесса. Текущей должна стать таблица страниц нового процесса. Обычно это делается