Сегментная и страничная виртуальная память
В большинстве систем со страничным диспетчером свободная память отслеживается при помощи битовой маски физических страниц. В этой маске свободной странице соответствует 1, а занятой – 0. Если кому-то нужна граница, система просто ищет в этой маске установленный бит. В результате виртуальное пространство программы может оказаться отображено на Физические адреса очень причудливым образом, но это никого не волнует – скорость доступа ко всем страницам одинакова (рис. 5.4).
Рис. 5.4. Распределение адресного пространства по физической памяти
В-четвертых, система может обеспечивать не только защиту программ друг от друга, но в определенной мере и защиту программы от самой себя – например, от ошибочной записи данных на место кода или попытки исполнить данные.
В-пятых, разные задачи могут использовать общие области памяти для взаимодействия или, скажем, просто для того, чтобы работать с одной копией библиотеки подпрограмм.
Перечисленные преимущества настолько серьезны, что считается невозможным реализовать многозадачную систему общего назначения, такую как UNIX или System/390 на машинах без диспетчера памяти.
Для систем реального времени, впрочем, виртуальная память оказывается скорее вредна, чем бесполезна: наличие диспетчера памяти увеличивает объем контекста процесса (это понятие подробнее обсуждается в разд. "Вытесняющая многозадачность"), воспользоваться же главным преимуществом – возможностью страничного обмена – задачи реального времени в полной мере не могут. Поэтому такие системы, даже работающие на процессорах со встроенным диспетчером памяти, часто этот диспетчер не используют. Даже если виртуальная память доступна, система РВ (реального времени) обязана предоставлять средства блокировки кода и данных (не обязательно всех) пользовательского процес са в физической памяти.
Отдельной проблемой при разработке системы со страничной или сегментной адресацией является выбор размера страницы или максимального размера сегмента. Этот размер определяется шириной соответствующего битового поля адреса и поэтому должен быть степенью двойки.
С одной стороны, страницы не должны быть слишком большими, так как это может привести к внутренней фрагментации и перекачке слишком больших объемов данных при сбросе страниц на диск. С другой стороны, страницы не должны быть слишком маленькими, так как это приведет к чрезмерному увеличению таблиц трансляции, требуемого объема кэша дескрипторов и т. д.
В реальных системах размер страницы меняется от 512 байт у машин семейства VAX до нескольких килобайт. Например, х86 имеет страницу размером 4 Кбайт. Некоторые диспетчеры памяти, например у МС6801/2/30, имеют переменный размер страницы – система при запуске программирует диспетчер и устанавливает, помимо прочего, этот размер, и дальше работает со страницами выбранного размера. У процессора i860 размер страницы переключается между 4 Кбайтами и 4 Мбайтами.
С сегментными диспетчерами памяти ситуация сложнее. С одной стороны, хочется, чтобы один программный модуль помешался в сегмент, поэтому сегменты обычно делают большими, от 32 Кбайт и более. С другой стороны, хочется, чтобы в адресном пространстве можно было сделать много сегментов. Кроме того, может возникнуть проблема: как быть с большими неразделимыми объектами, например хэш-таблицами компиляторов, под которые часто выделяются сотни килобайт.
В результате ряд машин предоставляет двухступенчатую виртуальную память – сегментную адресацию, в которой каждый сегмент, в свою очередь, разбит на страницы. Это дает ряд мелких преимуществ, например, позволяет давать права доступа сегментам, а подкачку с диска осуществлять постранично. Таким образом, организована виртуальная память в IBM System 370 и ряде других больших компьютеров, а также в х86. Правда, в последнем виртуальная память используется несколько странным образом.
Адресное пространство х86
Х86 может работать с двумя типами адресов:
32- разрядным адресом, в котором 16 бит задают смещение в сегменте, 14 бит – номер сегмента и 2 бита используются для разных загадочных целей. При этом размер сегмента не более 64 Кбайт, а общий объем виртуальной памяти не превышает 1 Гбайта.
48- разрядным адресом, в котором смещение в сегменте занимает 32 бита. В этом случае размер сегмента может быть до 4 Гбайт, а общий объем виртуальной памяти до 244 байт. В обоих случаях сегмент может быть разбит на страницы по 4 Кбайт.
При этом сегментная часть адреса и его смещение лежат в разных регистрах, и с ними можно работать раздельно. В реальном режиме возможность такой работы порождает весь "зоопарк моделей памяти", с которыми знакомы те, кто писал на С для MS DOS.
В защищенном режиме х86 большинство систем программирования выделяют программе один сегмент с 32-разрядным смещением, и программа живет там так, будто это обычная машина с 32-разрядным линейным адресным пространством. Так поступают все известные авторам реализации Unix для х86, ряд так называемых расширителей DOS (DOS extenders), Oberon/386, Novell Netware, реализации Win32 и т. д.