Сегментный способ организации виртуальной памяти

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

Преобразование имени сегмента в его порядковый номер осуществит система программирования, а операционная система будет размещать сегменты в память и для каждого сегмента получит информацию о его начале. Таким образом, вир­туальный адрес для этого способа будет состоять из двух полей – номера сегмента и смещения относительно начала сегмента. Соответствующая иллюстрация при­ведена на рис. 1.7. На этом рисунке изображен случай обращения к ячейке, вир­туальный адрес которой равен сегменту с номером 11 и смещением от начала этого сегмента, равным 612. Операционная система разместила данный сегмент в памяти начиная с ячейки с номером 19700.

Каждый сегмент, размещаемый в памяти, имеет соответствующую информаци­онную структуру, часто называемую дескриптором сегмента. Именно опера­ционная система строит для каждого исполняемого процесса соответствующую таблицу дескрипторов сегментов и при размещении каждого из сегментов в опе­ративной или внешней памяти в дескрипторе отмечает его текущее местополо­жение. Если сегмент задачи в данный момент находится в оперативной памяти, то об этом делается пометка в дескрипторе. Как правило, для этого используется «бит присутствия» (present). В этом случае в поле «адрес» диспетчер памяти за­писывает адрес физической памяти, с которого сегмент начинается, а в поле «длина сегмента» (limit) указывается количество адресуемых ячеек памяти. Это поле используется не только для того, чтобы размещать сегменты без наложения один на другой, но и для того, чтобы проконтролировать, не обращается ли код исполняющейся задачи за пределы текущего сегмента. В случае превышения длины сегмента вследствие ошибок программирования мы можем говорить о нарушении адресации и с помощью введения специальных аппаратных средств генерировать сигналы прерывания, которые позволят фиксировать (обнаружи­вать) такого рода ошибки.

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

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

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

Для решения проблемы замещения (определения того сегмента, который должен быть либо перемещен во внешнюю память, либо просто замещен новым) исполь­зуются следующие правила:

• FIFO (first in – first out, что означает: «первый пришедший первым и выбывает»);

• LRU (least recently used, что означает «последний из недавно исполь­зованных» или, иначе говоря, «дольше всего неиспользуемый»);

• LFU (least frequently used, что означает: «используемый реже всех ос­тальных»);

• случайный (random) выбор сегмента.

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

Алгоритм FIFO ассоциирует с каждым сегментом время, когда он был помещен в память. Для замещения выбирается наиболее старый сегмент. Учет времени не обязателен, когда все сегменты в памяти связаны в FIFO-очередь и каждый помещаемый в память сегмент добавляется в хвост этой очереди. Алгоритм учи­тывает только время нахождения сегмента в памяти, но не учитывает факти­ческое использование сегментов. Например, первые загруженные сегменты про­граммы могут содержать переменные, используемые на протяжении работы всей программы. Это приводит к немедленному возвращению к только что замещен­ному сегменту.

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

Достоинства сегментного способа организации виртуальной памяти: 1) появляется возмож­ность при загрузке программы на исполнение размещать ее в памяти не целиком, а «по мере необходимости»; 2) некоторые программные модули могут быть разделяемыми.

Однако у сегментного способа распределения памяти есть и недостатки. Прежде всего, из рис. 1.7 видно, что для получения доступа к искомой ячейке памяти не­обходимо потратить намного больше времени. Мы должны сначала найти и про­читать дескриптор сегмента, а уже потом, используя данные из него о местонахо­ждении нужного нам сегмента, можем вычислить и конечный физический адрес. Для того чтобы уменьшить эти потери, используется кэширование – то есть те дескрипторы, с которыми мы имеем дело в данный момент, могут быть размеще­ны в сверхоперативной памяти (специальных регистрах, размещаемых в процес­соре).

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

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

Примером использования сегментного способа организации виртуальной памя­ти является операционная система для ПК OS/2 первого поколения, которая была создана для процессора i80286. В этой ОС в полной мере использованы ап­паратные средства микропроцессора, который специально проектировался для поддержки сегментного способа распределения памяти.