Глава 4 (1085728), страница 4
Текст из файла (страница 4)
MOV REG,1000
о
на делает это для того, чтобы скопировать содержимое памяти по адресу 1000 в регистр REG (или наоборот, в зависимости от компьютера). Адреса могут формироваться с использованием индексации, базовых регистров, сегментных регистров и другими путями.
Рис. 4.9. Расположение и функции диспетчера памяти (MMU). Здесь диспетчер памяти показан как часть микросхемы процессора, потому что в наши дни это обычно так и есть. Но логически он мог бы быть отдельной микросхемой, и так было некоторое время назад
Эти программно формируемые адреса, называемые виртуальными адресами, формируют виртуальное адресное пространство. На компьютерах без виртуальной памяти виртуальные адреса подаются непосредственно на шину памяти и вызывают для чтения или записи слово в физической памяти с тем же самым адресом. Когда используется виртуальная память, виртуальные адреса не передаются напрямую шиной памяти. Вместо этого они передаются диспетчеру памяти (MMU — Memory Management Unit), который отображает виртуальные адреса на физические адреса памяти, как продемонстрировано на рис. 4.9.
Очень простой пример того, как работает отображение, приведен на рис. 4.10. Мы рассматриваем компьютер, который может формировать 16-разрядные адреса, от 0 до 64 К. Это виртуальные адреса. Однако у этого компьютера только 32 Кбайт физической памяти, поэтому, хотя программы размером 64 Кбайт могут быть написаны, они не могут целиком быть загружены в память и запущены. Полная копия образа памяти программы размером до 64 Кбайт должна присутствовать на диске, но в таком виде, чтобы ее можно было по мере надобности переносить в память по частям.
Пространство виртуальных адресов разделено на единицы, называемые страницами. Соответствующие единицы в физической памяти называются страничными блоками (page frame). Страницы и их блоки имеют всегда одинаковый размер. В этом примере они равны 4 Кбайт, но в реальных системах использовались размеры страниц от 512 байт до 64 Кбайт. Имея 64 Кбайт виртуального адресного пространства и 32 Кбайт физической памяти, мы получаем 16 виртуальных страниц и 8 страничных блоков. Передача данных между ОЗУ и диском всегда происходит в страницах.
Когда программа пытается получить доступ к адресу 0, например, используя команду
MOV REG,О
виртуальный адрес 0 передается диспетчеру памяти (MMU). Диспетчер памяти видит, что этот виртуальный адрес попадает на страницу 0 (от 0 до 4095), которая отображается страничным блоком 2 (от 8192 до 12287). Диспетчер переводит виртуальный адрес 0 в физический адрес 8192 и выставляет последний на шину. Память ничего не знает о диспетчере памяти и видит просто запрос на чтение или запись слова по адресу 8192, который и выполняет. Таким образом, диспетчер памяти эффективно отображает все виртуальные адреса между 0 и 4095 на физические адреса от 8192 до 12287.
Рис. 4.10. Связь между виртуальными и физическими адресами, получаемая с помощью таблицы страниц
Точно так же инструкция
MOV REG, 8192
преобразуется в команду
MOV REG, 24576
поскольку виртуальный адрес 8192 находится на виртуальной странице 2, а эта страница отображается на физический страничный блок 6 (физические адреса от 24576 до 28671). В качестве третьего примера рассмотрим виртуальный адрес 20500, который адресует 20-й байт от начала виртуальной страницы 5 (виртуальные адреса от 20480 до 24575) и отображается на физический адрес 12288 + 20 = 12308.
Сама по себе возможность отображения 16 виртуальных страниц на любой из восьми страничных блоков с помощью установки соответствующей карты в диспетчере памяти не решает проблемы, заключающейся в том, что размер виртуального адресного пространства больше физической памяти. Так как у нас есть только восемь физических страничных блоков, только восемь виртуальных страниц на рис. 4.10 воспроизводятся в физической памяти. Другие страницы, обозначенные на рисунке крестиками, не отображаются. В фактическом аппаратном обеспечении страницы, физически присутствующие в памяти, отслеживаются с помощью бита присутствия/отсутствия.
Что происходит, если программа пытается воспользоваться неотображаемой страницей, например, с помощью инструкции
MOV REG, 32780
которая обращается к байту 12 на виртуальной странице 8 (начинающейся с адреса 32768)? Диспетчер памяти замечает, что страница не отображается (обозначена крестиком на рисунке), и инициирует прерывание центрального процессора, передающее управление операционной системе. Такое прерывание называется ошибкой из-за отсутствия страницы или страничным прерыванием (page fault). Операционная система выбирает малоиспользуемый страничный блок и записывает его содержимое на диск. Затем она считывает с диска страницу, на которую произошла ссылка, в только что освободившийся блок, изменяет карту отображения и запускает заново прерванную команду.
Например, если операционная система решает удалить из оперативной памяти страничный блок 1, она загружает виртуальную страницу 8 по физическому адресу 4 К и производит два изменения в карте диспетчера памяти. Во-первых, отмечается содержимое виртуальной страницы 1 как неотображаемое для того, чтобы перехватывать в будущем любые попытки обращения к виртуальным адресам между 4 К и 8 К. Затем заменяется крест в записи для виртуальной страницы 8 на номер 1, так что когда прерванная команда будет выполняться заново, она отобразит виртуальный адрес 32780 на физический адрес 4108.
Теперь рассмотрим диспетчер памяти изнутри, чтобы увидеть, как он работает, и понять, почему мы выбрали размер страницы, являющийся степенью числа 2. На рис. 411 представлен пример виртуального адреса 8196 (0010000000000100 в двоичном виде), который отображается с использованием карты диспетчера памяти на рис 4.10. Входящий 16-разрядный виртуальный адрес разделяется на 4-разрядный номер страницы и 12 битов смещения. При 4 битах под номер страницы в нашей системе может существовать 16 страниц, а с 12 битами смещения мы можем адресоваться ко всем 4096 байтам внутри страницы.
Номер страницы используется в качестве индекса в таблице страниц, выдающей номер страничного блока, соответствующего виртуальной странице. Если бит Присутствия/отсутствия равен 0, управление переходит к операционной системе. Если этот бит равен 1, то номер страничного блока, найденный в таблице страниц, записывается в три старших бита выходного регистра, а 12 битов смещения копируются без изменения из входящего виртуального адреса. Все вместе они составляют 15-разрядный физический адрес. Затем выходной регистр помещается на шину памяти как адрес физической памяти
Таблицы страниц
В простейшем случае отображение виртуальных адресов на физические происходит так, как мы только что описали. Виртуальный адрес делится на номер виртуальной страницы (старшие биты) и сдвиг (младшие биты) Например, при 16-разрядных адресах и размере страницы 4 Кбайт старшие 4 бита могут указывать одну из 16 виртуальных страниц, а нижние 12 бит могут определять байт смещения (от 0 до 4095) внутри выбранной страницы. Однако разбиение страницы на 3,5 или какое-нибудь другое число битов также возможно. Разные части подразумевают различные размеры страниц.
Номер виртуальной страницы используется как индекс в таблице страниц для поиска записи этой страницы. По записи в таблице страниц находится номер физического блока страницы (если это имеет место). Данный номер присоединяется к старшим разрядам числа смещения, замещая номер виртуальной страницы и тем самым формируя физический адрес, который может быть послан в память.
Назначение таблицы страниц заключается в отображении виртуальных страниц на страничные блоки. Говоря математически, таблица страниц — это функция, имеющая в качестве аргумента номер виртуальной страницы и получающая в результате номер физического блока. Используя результат действия этой функции, поле виртуальной страницы в виртуальном адресе может быть заменено полем страничного блока, таким образом, формируется физический адрес.
Несмотря на столь простое описание, нам придется столкнуться с двумя важными проблемами:
1. Таблица страниц может быть слишком большой.
2. Отображение должно быть быстрым.
Первый пункт следует из того факта, что современные компьютеры используют по крайней мере 32-разрядные виртуальные адреса. При размере страницы, скажем, 4 Кбайт, 32-разрядное адресное пространство будет состоять из одного миллиона страниц, а 64-разрядное адресное пространство будет включать в себя намного больше страниц, чем то количество, с которым вы захотите иметь дело. При одном миллионе страниц в виртуальном адресном пространстве таблица страниц должна состоять из одного миллиона записей. И помните, что каждый процесс нуждается в своей собственной таблице страниц (потому что у него есть свое собственное виртуальное адресное пространство).
Второй пункт — это вывод из того факта, что преобразование виртуальных адресов в физические должно быть выполнено для каждого обращения к ячейке памяти. Типичная команда процессора включает в себя слово-команду и часто также операнд памяти. В результате необходимо сделать 1,2 или иногда больше обращений к таблице страниц за команду. Если выполнение команды занимает, скажем, 4 нc, то поиск в таблице страниц должен быть сделан меньше, чем за 1 нc, чтобы преобразование виртуальных адресов не стало главным узким местом системы.
Потребность в огромном, но при этом быстром страничном отображении накладывает существенные ограничения на способы построения компьютеров. Хотя проблема наиболее серьезно встает для старших моделей семейства, она также появляется и для младших моделей, когда стоимость и соотношение цена/производительность имеют критическое значение. В этом и следующих разделах мы рассмотрим устройство таблицы страниц в деталях и покажем несколько аппаратных решений, которые использовались в реальных компьютерах.
Простейшее конструкторское решение (по крайней мере, концептуально) заключается в поддержании таблицы страниц, состоящей из массива быстрых аппаратных регистров с одной записью для каждой виртуальной страницы, индексированного по номерам виртуальных страниц, как показано на рис. 4.11. Когда процесс запускается, операционная система загружает в регистры таблицу страниц процесса, данные берутся из копии, хранящейся в оперативной памяти. Во время выполнения процесса таблице страниц больше не нужно обращаться к памяти. Преимущество этого метода заключается в его простоте и отсутствии необходимости обращений к памяти во время преобразования адресов. Недостатком является его потенциально высокая стоимость (если таблица страниц велика). Необходимость загрузки полной таблицы в регистры при каждом контекстном переключении наносит ущерб производительности.
Другая крайность заключается в том, что таблица страниц целиком располагается в оперативной памяти. Тогда все необходимое оборудование состоит из одного-единственного регистра, указывающего на начало таблицы страниц. Такая схема позволяет изменять карту памяти при контекстном переключении путем перезагрузки только одного регистра. Конечно, она имеет свой недостаток: во время выполнения каждой инструкции программы требуется одно или несколько обращений к памяти для чтения записей таблицы страниц. По этой причине данный метод редко используется в своем чистом виде, но ниже мы изучим несколько его разновидностей, имеющих намного более высокую производительность.
Многоуровневые таблицы страниц
Чтобы обойти проблему необходимости постоянного хранения в памяти огромных таблиц страниц, многие компьютеры используют многоуровневую таблицу страниц. Простой пример представлен на рис. 4.12. На рис. 4.12, а изображен 32-разрядный виртуальный адрес, который разделен на 10-разрядное поле РT1, 10-разрядное поле РT2 и 12-разрядное поле Offset (смещение). Так как под смещение отведено 12 бит, страницы имеют размер 4 Кбайт, и их всего 220.
Секрет метода многоуровневой таблицы страниц заключается в том, чтобы избегать постоянного содержания в памяти всех таблиц страниц. В частности, те части, которые не нужны в данный момент, не должны храниться в памяти. Предположим, например, что процессу нужно 12 Мбайт, младшие 4 Мбайт памяти для текста программы, следующие 4 Мбайт для данных и старшие 4 Мбайт для стека. Между верхом данных и низом стека образуется гигантский свободный участок, который не используется.
На рис. 4.12, б мы видим, как в данном примере работает двухуровневая таблица страниц. Слева находится таблица страниц верхнего уровня с 1024 записями, соответствующими 10-разрядному полю РT1. Когда виртуальный адрес предстает перед диспетчером памяти, он сначала выделяет поле РT1 и использует его значение как индекс таблицы верхнего уровня. Каждая из этих 1024 записей представляет 4 М, потому что целое 4-гигабайтное (то есть 32-разрядное) виртуальное адресное пространство было нарезано на куски по 1024 байта.