Сегментная и страничная виртуальная память
Большинство реальных программ используют далеко не все адресное пространство процессора, соответственно таблица трансляции не обязательно держит все допустимые дескрипторы. Поэтому практически все диспетчеры памяти имеют еще один регистр – ограничитель длины таблицы трансляции. Страницы или сегменты, селектор которых превосходит ограничитель, не входят в виртуальное адресное пространство процесса. Как правило, диспетчер памяти имеет также кэш (cache) дескрипторов – быструю память с ассоциативным доступом. В этой памяти хранятся дескрипторы часто используемых страниц. Алгоритм доступа к памяти по виртуальному адресу page: off set состоит из следующих шагов (рис. 5.3).
Рис. 5.3. Блок-схема алгоритма диспетчера памяти
- Проверить, существует ли страница page вообще. Если страницы не существует, возникает особая ситуация ошибки сегментации (segmentation violation) (понятие особой ситуации (исключения) подробнее разбирается в Разделе 6).
- Попытаться найти дескриптор страницы в кэше.
- Если его нет в кэше, загрузить дескриптор из таблицы в памяти.
- Проверить, имеет ли процесс соответствующее право доступа к странице. Иначе также возникает ошибка сегментации.
- Проверить, находится ли страница в оперативной памяти. Если ее там нет, возникает особая ситуация отсутствия страницы или страничные отказ (page fault). Как правило, реакция на нее состоит в том, что вызывается специальная программа-обработчик (trap – ловушка), которая загружает требуемую страницу с диска. В многопоточных системах во время такой загрузки может исполняться другой процесс.
- Если страница есть в памяти, взять из ее дескриптора физический адрес phys_addr.
- Если мы имеем дело с сегментной адресацией, сравнить смещение в сегменте с длиной этого сегмента. Если смещение оказалось больше, также возникает ошибка сегментации.
- Произвести доступ к памяти по адресу phys_addr[offset].
Видно, что такая схема адресации довольно сложна. Однако в современных процессорах все это реализовано аппаратно и, благодаря кэшу дескрипторов и другим ухищрениям, скорость доступа к памяти получается почти такой же, как и при прямой адресации. Кроме того, эта схема имеет неоценимые преимущества при реализации многозадачных ОС.
Во-первых, мы можем связать с каждой задачей свою таблицу трансляции, а значит и свое виртуальное адресное пространство. Благодаря этому даже в многозадачных ОС мы можем пользоваться абсолютным загрузчиком. Кроме того, программы оказываются изолированными друг от друга, и мы можем обеспечить их безопасность.
Во-вторых, мы можем сбрасывать на диск редко используемые области виртуальной памяти программ – не всю программу целиком, а только ее часть. В отличие от оверлейных загрузчиков, программа при этом вообще не обязана знать, какая ее часть будет сброшена.
Другое дело, что в системах реального времени программе может быть нужно, чтобы определенные ее части никогда не сбрасывались на диск. Система реального времени обязана гарантировать время реакции, и это гарантированное время обычно намного меньше времени доступа к диску. Код, обрабатывающий событие, и используемые при этом данные должны быть всегда в памяти.
В-третьих, программа не обязана занимать непрерывную область физической памяти. При этом она вполне может видеть непрерывное виртуальное адресное пространство. Это резко упрощает борьбу с фрагментацией памяти, а в системах со страничной адресацией проблема внешней фрагментации физической памяти вообще снимается.