2.Внутреннее устройство Windows (гл. 5-7)
Шрифт:
Многие приложения, выполняемые в Windows, используют сравнительно небольшие объемы памяти из куч (обычно менее одного мегабайта). Для этого класса приложений диспетчер куч применяет политику наибольшей подгонки (best-fit policy), которая помогает сохранять небольшим «отпечаток» каждого процесса в памяти. Однако такая стратегия не масштабируется для больших процессов и многопроцессорных машин. B этих случаях доступная память в куче может уменьшиться из-за ее фрагментации. B сценариях, где лишь блоки определенного размера часто используются параллельно разными потоками, выполняемыми на разных процессорах, производительность ухудшается. Дело
Эти проблемы решаются применением кучи с малой фрагментацией (LFH), которая использует базовый уровень диспетчера куч и ассоциативные списки. B отличие от ситуации, в которой ассоциативные списки по умолчанию применяются как интерфейсные, если это разрешено другими параметрами куч, поддержка LFH включается, только когда приложение вызывает функцию HeapSetInformation. B случае больших куч значительная доля запросов на выделение обычно раскладывается на относительно небольшое число корзин (buckets) определенных размеров. Стратегия выделения памяти, применяемая LFH, заключается в оптимизации использования памяти для таких запросов за счет эффективной обработки блоков одного размера.
Для устранения проблем с масштабируемостью LFH раскрывает часто используемые внутренние структуры в набор слотов, в два раза больший текущего количества процессоров в компьютере. Закрепление потоков за этими слотами выполняется LFH-компонентом, называемым диспетчером привязки (affinity manager). Изначально LFH использует для распределения памяти первый слот, но, как только возникает конкуренция при доступе к некоторым внутренним данным, переключает текущий поток на другой слот. И чем больше конкуренция, тем большее число слотов задействуется для потоков. Эти слоты создаются для корзины каждого размера, что также увеличивает локальность и сводит к минимуму общий расход памяти.
Диспетчер куч предоставляет несколько средств, помогающих обнаруживать ошибки.
• Enable tail checking (включить проверку концевой части блока) B конец каждого блока помещается сигнатура, проверяемая при его освобождении. Если эта сигнатура полностью или частично уничтожается из-за переполнения буфера, куча сообщает о соответствующей ошибке.
• Enable free checking (включить проверку свободных блоков) Свободный блок заполняется определенным шаблоном, который проверяется, когда диспетчеру куч нужен доступ к этому блоку. Если процесс продолжает записывать в блок после его освобождения, диспетчер куч обнаружит изменения в шаблоне и сообщит об ошибке.
• Parameter checking (проверка параметров) Проверка параметров, передаваемых функциям куч.
• Heap validation (проверка кучи) Вся куча проверяется при каждом обращении к ней.
• Heap tagging and stack traces support (поддержка меток и трассировки стека) Это средство поддерживает задание меток для выделяемой памяти и/или перехват трассировок стека пользовательского режима при обращениях к куче, что помогает локализовать причину той или иной ошибки.
Первые три средства включаются по умолчанию, если загрузчик обнаруживает, что процесс запущен под управлением отладчика. (Отладчик может переопределить такое поведение и выключить эти средства.) Средства отладки для куч могут быть заданы установкой различных отладочных флагов в заголовке образа через утилиту gflags (см. раздел «Глобальные флаги Windows» в главе 3) или командой !heap в любом стандартном отладчике Windows.
Включение
Так как при проверке концевых частей блоков и шаблона свободных блоков могут обнаруживаться повреждения, произошедшие задолго до проявления собственно проблемы, предоставляется дополнительный инструмент отладки куч, pageheap, который переадресует все обращения к куче (или их часть) другомудиспетчеру куч. Pageheap является частью Windows Application Compatibility Toolkit, и его можно скачать с www.microsoft.com. Pageheap помещает выделенные блоки в конец страниц, поэтому при переполнении буфера возникнет нарушение доступа, что упростит выявление ошибочного кода. Блоки можно помещать и в начало страниц для обнаружения проблем, связанных с неполным использованием буферов (buffer underruns). (Такие ситуации — большая редкость.) Pageheap также позволяет защищать освобожденные страницы от любых видов доступа для выявления ссылок на блоки после их освобождения.
Заметьте, что применение pageheap может привести к нехватке адресного пространства, так как выделение даже очень малых блоков памяти сопряжено с существенными издержками. Также может ухудшиться производительность из-за увеличения количества ссылок на обнуленные страницы, потери локальности и частых вызовов для проверки структур кучи. Чтобы уменьшить негативное влияние на производительность, pageheap можно использовать только для блоков определенных размеров, конкретных диапазонов адресов и т. д.
ПРИМЕЧАНИЕ Подробнее о pageheap см. статью 286470 в Microsoft Knowledge Base .
Хотя 32-разрядные версии Windows поддерживают до 128 Гб физической памяти (см. таблицу 2–4 в главе 2), размер виртуального адресного пространства любого 32-разрядного пользовательского процесса по умолчанию равен 2 Гб (при указании загрузочных параметров /3GB и /USERVA в Boot.ini этот размер составляет 3 Гб). Чтобы 32-разрядный процесс мог получить доступ к большему объему физической памяти, Windows поддерживает набор функций под общим названием Address Windowing Extensions (AWE). Так, в системе под управлением Windows 2000 Advanced Server с 8 Гб физической памяти серверное приложение базы данных может с помощью AWE использовать под кэш базы данных до 6 Гб памяти.
Выделение и использование памяти через функции AWE осуществляется в три этапа.
1. Выделение физической памяти.
2. Создание региона виртуального адресного пространства — окна, на которое будут проецироваться представления физической памяти.
3. Проецирование на окно представлений физической памяти.
Для выделения физической памяти приложение вызывает Windows-функцию AllocateUserPhysicalPages. (Эта функция требует, чтобы у пользователя была привилегия Lock Pages In Memory.) Затем приложение обращается к Windows-функции VirtucriAlloc с флагом MEM_PHYSICAL, чтобы создать окно в закрытой части адресного пространства процесса, на которое проецируется (частично или полностью) ранее выделенная физическая память. Память, выделенная через AWE, может быть использована почти всеми функциями Windows API. (Например, функции Microsoft DirectX ее не поддерживают.)