Библиотека сайта rus-linux.net
Что каждый программист должен знать о памяти. Виртуальная память
Оригинал: What every programmer should know about memoryАвтор: Ulrich Drepper
Дата публикации: 09.10.2007
Перевод: Капустин С.В.
Дата перевода: 19.03.2009
4.2 Многоуровневые таблицы страниц
Страницы размером 4Мб не являются нормой. Они бы расходовали много лишней памяти, так как многие операции, которые выполняет операционная система, требуют выравнивания страниц памяти. Со страницами размером 4Кб (норма для 32-битных машин и все еще часто для 64-битных) часть виртуального адреса "смещение" имеет размер всего 12 бит. Это оставляет 20 бит для выбора из каталога страниц. Таблица с 220 записями непрактична. Даже если каждая запись будет размером всего 4 байта, размер таблицы будет 4Мб. Тогда большая часть физической памяти системы будет отдана на таблицы страниц, так как каждый процесс может иметь свою таблицу страниц.
Решение состоит в использовании нескольких уровней таблицы страниц. Они могут представлять огромный разреженный каталог страниц, где неиспользуемые регионы не требуют выделения памяти. Следовательно, представление намного более компактное и есть возможность для многих процессов в памяти иметь каталоги страниц без существенного влияния на производительность.
Сегодня наиболее сложные структуры таблиц страниц содержат 4 уровня. Рисунок 4.2 показывает схему такой структуры.
Рисунок 4.2: 4-уровневое преобразование адресов
Виртуальный адрес в этом примере разбит, по крайней мере, на 5 частей. 4 части являются индексами различных каталогов. Для ссылок на каталог 4-го уровня используется специальный регистр процессора. Содержимое каталога на уровнях с 4 по 2 - это ссылки на каталог уровня ниже на единицу. Если запись каталога помечена как пустая, она очевидно не должна указывать на низлежащий каталог. За счет этого достигается разреженность и компактность дерева таблиц страниц. Записи каталога уровня 1 - это часть физического адреса плюс дополнительные данные как, например, разрешения на доступ.
Чтобы определить физический адрес, соответствующий виртуальному адресу, процессор сначала определяет адрес наивысшего уровня в каталоге. Этот адрес обычно хранится в регистре. Затем процессор берет часть виртуального адреса, соответствующую индексу этого каталога, и использует этот индекс, чтобы выбрать подходящую запись. Эта запись - адрес следующего каталога, который проиндексирован с помощью следующей части виртуального адреса. Этот процесс продолжается, пока не достигнет каталога уровня 1, где значение записи каталога - это старшие разряды физического адреса. Младшие разряды физического адреса берутся из битов "смещения" виртуального адреса. Этот процесс называется прогулкой по дереву страниц. Некоторые процессоры (как x86 и x86-64) выполняют эту операцию аппаратно, другие прибегают к помощи операционной системы.
Каждому запущенному в системе процессу, возможно, понадобится собственное дерево таблиц страниц. Частичное разделение деревьев возможно, но это скорее исключение. Следовательно, для производительности и масштабируемости предпочтительно, чтобы память, отведенная под деревья таблиц страниц, была как можно меньше. Идеальный случай для этого, если используемая память расположена компактно в виртуальном адресном пространстве; какие именно физические адреса используются - значения не имеет. Маленькая программа может обойтись использованием на уровнях 2,3,4 только по одному каталогу и несколькими каталогами на уровне 1. На x86-64 со страницами размера 4Кб и 512 записями в каталоге это позволяет адресовать 2Мб с помощью 4-х каталогов (по одному на каждом уровне). 1Гб непрерывной памяти может быть адресован, используя по одному каталогу на уровнях со 2-го по 4-й и 512 каталогов на уровне 1.
Однако предполагать, что вся память может быть выделена одним куском, будет слишком большим упрощением. Из соображений гибкости области стека и кучи процесса в большинстве случаев выделяются на противоположных концах адресного пространства. Это позволяет каждой области при необходимости расти так как только возможно. Это означает, что скорее всего, будет 2 каталога на уровне 2 и соответственно больше каталогов на низлежащем уровне.
Но даже этот случай не всегда имеет место на практике. Из соображений безопасности различные части исполняемого процесса (код, данные, куча, стек, разделяемые библиотеки) отображаются на случайно выбранные (рандомизированные) адреса (см. [1]). Рандомизации подвергается относительное расположение разных частей, из этого следует, что используемые участки памяти могут быть в любой части виртуального адресного пространства. Если рандомизировать только несколько битов адреса, можно ограничить область, в которой находятся используемые участки виртуального адресного пространства; но, конечно, в большинстве случаев невозможно ограничить процесс использованием только одного или двух каталогов на уровнях 2 и 3.
Если производительность намного важнее безопасности, рандомизация может быть отключена. Тогда операционная система обычно, по крайней мере, загружает все исполняемые библиотеки в виртуальную память одним непрерывным куском.
Назад | Оглавление | Вперед |