Смекни!
smekni.com

Операционные системы 5 (стр. 37 из 43)

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

5.1. Основные задачи управления памятью

Основная память (она же ОЗУ) является важнейшим ресурсом, эффективное использование которого решающим образом влияет на общую производительность системы.

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

· выделение памяти для процесса пользователя при его запуске и освобождение этой памяти при завершении процесса;

· обеспечение настройки запускаемой программы на выделенные адреса памяти;

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

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

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

· предоставление процессам возможностей получения и освобождения дополнительных областей памяти в ходе работы;

· эффективное использование ограниченного объема основной памяти для удовлетворения нужд всех работающих процессов, в том числе с использованием дисков как расширения памяти;

· изоляция памяти процессов, исключающая случайное или намеренное несанкционированное обращение одного процесса к областям памяти, занимаемым другим процессом;

· предоставление процессам возможности обмена данными через общие области памяти.

5.2. Виртуальные и физические адреса

Понятие «адрес памяти» может рассматриваться с двух точек зрения. С одной стороны, при написании любой программы ее автор либо явно указывает, по каким адресам должны размещаться переменные и команды (так бывает при программировании на языке ассемблера), либо присвоение конкретных адресов доверяется системе программирования. Те адреса памяти, которые записаны в программе, принято называть виртуальными адресами.

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

В ЭВМ первого поколения не делалось различия между виртуальными и физическими адресами: в программе требовалось указывать физические адреса. Это означало, что такая программа могла правильно работать, только если сама программа и все ее данные при каждом запуске (и на любом компьютере) должны были размещаться по одним и тем же физическим адресам. Такой подход стал крайне неудобным, как только была поставлена задача передать распределение памяти под управление ОС.

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

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

Есть два принципиально разных ответа на этот вопрос.

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

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

5.3. Распределение памяти без использования виртуальных адресов

5.3.1. Настройка адресов

Если в программе используются значения физических адресов, то правильность ее работы зависит от того, по каким адресам загружена в память сама программа. Это особенно очевидно для команд перехода: если в программе есть команда «Перейти по адресу 1000», то сдвиг этой программы в памяти приведет к тому, что переход будет выполнен на совсем другую команду, хотя и по тому же адресу.

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

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

Более поздние архитектуры ЭВМ позволили в значительной мере упростить дело за счет использования относительной адресации – указания адреса как смещения относительно значения в некотором базовом регистре. Теперь настройка требовалась лишь для нескольких команд, загружающих значения в базовые регистры. Более того, для многих не слишком сложных программ стало возможно обойтись вообще без словаря перемещений (например, если все адреса указаны только как смещения относительно начала программы). Подобные программы, способные без изменений правильно работать при загрузке по любому адресу, называются позиционно-независимыми, в отличие от перемещаемых программ, требующих настройки адресов.

В системе MS-DOS все файлы типа COM содержат позиционно-независимые программы, а файлы EXE – перемещаемые.

5.3.2. Распределение с фиксированными разделами

При этом способе распределения памяти администратор системы заранее, при установке ОС, выполняет разбиение всей имеющейся памяти на несколько разделов. Как правило, формируются разделы разных размеров. Допускается также определение большого раздела как суммы нескольких примыкающих друг к другу меньших разделов, как показано на рис. 5‑1.

Рис. 5‑1

Возможны два варианта организации работы с фиксированными разделами.

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

· В более развитых системах программа хранится в перемещаемом формате, а при ее запуске система выбирает наиболее подходящий по размеру свободный раздел. При отсутствии такового программа ожидает.

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

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

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

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