1.Внутреннее устройство Windows (гл. 1-4)
Шрифт:
ЭКСПЕРИМЕНТ: наблюдение за использованием пула подкачиваемой памяти для кустов реестра
Административных утилит, которые показывали бы объем памяти из подкачиваемого пула, используемой кустами реестра вместе с профилями пользователей, в Windows 2000 нет. Однако команда !reg dump-pool отладчика ядра сообщает не только число страниц, задействованных каждым загруженным кустом, но и количество страниц, занятых постоянными и переменными данными. B конце отчета команда выводит суммарный объем памяти, занятой кустами реестра, (Учтите, что эта команда показывает лишь последние 32 символа в имени куста.)
ЭКСПЕРИМЕНТ:
B Windows XP и Windows Server 2003 статистику по использованию памяти кустами реестра можно просмотреть командой /reg hivelist. Вывод команды включает размеры постоянных (сохраняемых на диске) и переменных данных, число активных представлений и количество представлений, заблокированных в памяти:
Здесь куст профиля для учетной записи Administrator (полный путь к которому, \Documents and Settings\Administrator\ntuser.dat, в выводе обрезан) имеет 116 спроецированных представлений и размер около 4 Мб (0х3f000 в шестнадцатеричной форме). Команда /reg viewlist показывает спроецированные представления заданного куста. Вот как выглядит вывод этой команды при ее выполнении применительно к кусту UsrClass.dat, который был показан как первый куст в выводе команды /reg hivelist:
B этом выводе показаны адреса двух представлений, которые команда hivelist сообщила для куста в столбце ViewAddress. Используя команду db отладчика ядра для получения содержимого памяти по адресу первого представления, вы обнаружите, что это проекция базового блока куста Гона распознается по сигнатуое regf):
Для работы с дискретными адресами, ссылающимися на данные кустов в памяти, диспетчер конфигурации использует стратегию, аналогичную применяемой диспетчером памяти Windows для проецирования виртуальных адресов памяти на физические. Двухуровневая схема, принятая для диспетчера конфигурации, показана на рис. 4–7. Ha входе принимается индекс ячейки (т. е. смещение в файле куста), а на выходе возвращается адрес блока, в который попадает индекс данной ячейки, и адрес блока, в котором находится указанная ячейка. Вспомните, что в приемнике может быть более одного блока, а куст разрастается за счет увеличения размеров приемников. Ввиду этого Windows всегда отводит под приемник непрерывную область памяти, и все его блоки находятся в одном и том же представлении, принадлежащем диспетчеру кэша (в Windows XP и Windows Server 2003), или в одной и той же части пула подкачиваемой памяти.
Диспетчер конфигурации реализует такое проецирование, разбивая индекс ячейки на логические поля, — точно так же поступает и диспетчер памяти с виртуальными адресами. Windows интерпретирует первое поле индекса ячейки как индекс каталога карты ячеек куста. B каталоге карты ячеек имеется 1024 элемента, каждый из которых ссылается на таблицу карты ячеек, а каждая таблица в свою очередь содержит 512 элементов. Элемент в таблице карты ячеек определяется вторым полем индекса ячейки. B этом элементе содержатся адреса приемника и блоков с ячейкой в памяти. B Windows XP и Windows Server 2003 не все приемники обязательно проецируются в память, и, если поиск ячейки дает нулевой адрес, диспетчер конфигурации проецирует приемник в память, при необходимости отменяя проецирование другого приемника из своего списка.
Ha завершающем этапе процесса проецирования диспетчер конфигурации интерпретирует последнее поле индекса ячейки как смещение в найденном блоке для определения точного местонахождения ячейки в памяти. При инициализации куста диспетчер конфигурации динамически создает таблицы сопоставлений с записями для всех блоков куста, а в дальнейшем добавляет и удаляет таблицы из каталога ячеек по мере изменения размера куста.
Для интеграции пространства имен реестра с общим пространством имен ядра диспетчер конфигурации определяет тип объектов «раздел реестра». Он помещает такой объект с именем Registry в корень пространства имен Windows и использует его как точку входа в реестр. Regedit показывает имена разделов в виде HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet, но подсистема Windows транслирует эти имена в соответствии с пространством имен своих объектов (например, \Registry\Machine\System\CurrentControlSet). Диспетчер объектов, анализируя подобное имя, распознает ссылку на объект Registry и тут же передает остальную часть имени диспетчеру конфигурации. Последний берет на себя дальнейший разбор имени, просматривая свое внутреннее дерево куста для поиска нужного раздела или параметра. Прежде чем описывать последовательность действий при типичной операции с реестром, нужно обсудить объекты «раздел реестра» и блоки управле-ния разделом (key control blocks). Всякий раз, когда программа создает или открывает раздел реестра, диспетчер объектов передает ей описатель для ссылки на этот раздел. Описатель соответствует объекту «раздел реестра», созданному диспетчером конфигурации с участием диспетчера объектов. Опираясь на диспетчер объектов, диспетчер конфигурации использует все предоставляемые им преимущества в защите объектов и учете ссылок.
Для каждого открытого раздела реестра диспетчер конфигурации создает блок управления разделом. B таком блоке хранится полный путь раздела, индекс ячейки узла раздела, к которому относится данный блок, и флаг, уведомляющий диспетчер конфигурации, надо ли удалять ячейку раздела (на которую ссылается данный блок) после закрытия последнего описателя раздела. Windows помещает все блоки управления разделами в хэш-таблицу, что обеспечивает быстрый поиск нужного блока по имени. Объекты «раздел реестра» указывают на соответствующие блоки управления, и, если два приложения открывают один и тот же раздел реестра, каждое получает свой объект, указывающий на общий блок управления.
Приложение, открывая существующий раздел реестра, начинает с того, что сообщает его имя API-функции реестра, которая вызывает процедуру разбора имени, принадлежащую диспетчеру объектов. Найдя нужный объект «раздел реестра» в пространстве имен диспетчера конфигурации, диспетчер объектов возвращает ему полученный путь. Диспетчер конфигурации, используя структуры данных куста, содержащиеся в памяти, ищет указанный раздел среди всех разделов и подразделов. Если он находит ячейку раздела, поиск продолжается в дереве блоков управления разделами, что позволяет узнать, открыт ли данный раздел (тем же или другим приложением). Процедура поиска оптимизирована так, чтобы поиск всегда начинался с ближайшего предка с уже открытым блоком управления. Например, если приложение открывает \Registry\Machine\ Keyl\Subkey2 в то время, как \Registry\Machine уже открыт, то процедура разбора в качестве отправной точки использует блок управления разделом \Registry\Machine. Если раздел открыт, диспетчер конфигурации увеличивает счетчик ссылок в блоке управления этим разделом. B ином случае диспетчер конфигурации создает новый блок управления и помещает его в дерево. Далее диспетчер конфигурации создает объект «раздел реестра», передает указатель на него блоку управления разделом и возвращает управление диспетчеру объектов, который передает приложению описатель.
Когда приложение создает новый раздел реестра, диспетчер конфигурации сначала ищет для нового раздела ячейку родительского раздела. Далее он находит список свободных ячеек куста, в котором будет находиться новый раздел, и определяет, есть ли достаточно большие ячейки для размещения ячейки нового раздела. Если таковых нет, диспетчер конфигурации создает новый приемник и помещает в него ячейку, а остальное свободное пространство приемника регистрирует в списке свободных ячеек. Новая ячейка раздела заполняется соответствующей информацией, включая имя раздела. Диспетчер конфигурации добавляет ячейку раздела в список подразделов ячейки родительского раздела. Наконец, система сохраняет в новой ячейке индекс родительской ячейки.