Марк Руссинович - 2.Внутреннее устройство Windows (гл. 5-7)
- Название:2.Внутреннее устройство Windows (гл. 5-7)
- Автор:
- Жанр:
- Издательство:неизвестно
- Год:неизвестен
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Марк Руссинович - 2.Внутреннее устройство Windows (гл. 5-7) краткое содержание
Продолжение книги "Внутреннее устройство Microsoft Windows" — 5 и 7 главы.
2.Внутреннее устройство Windows (гл. 5-7) - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Функции диспетчера куч локализованы в двух местах: в NtdlLdll и Ntoskrnl.exe. API-функции подсистем (вроде API-функций Windows-куч) вызывают функции из Ntdll, а компоненты исполнительной системы и драйверы устройств — из NtoskrnL Родные интерфейсы (функции с префиксом Rtl) доступны только внутренним компонентам Windows и драйверам устройств режима ядра. Документированный интерфейс Windows API для куч (функции с префиксом Heap ) представляют собой тонкие оболочки, которые вызывают родные функции из NtdlLdll Кроме того, для поддержки устаревших Windows-приложений предназначены унаследованные API-функции (с префиксом Local или GlobaP). K наиболее часто используемым Windows-функциям куч относятся:
• HeapCreate или HeapDestroy — соответственно создает или удаляет кучу. При создании кучи можно указать начальные размеры зарезервированной и переданной памяти;
• HeapAlloc — выделяет блок памяти из кучи;
• HeapFree — освобождает блок, ранее выделенный через HeapAlloc
• HeapReAlloc — увеличивает или уменьшает размер уже выделенного блока;
• HeapLock и HeapUnlock — управляют взаимным исключением (mutual exclusion) операций, связанных с обращением к куче;
• HeapWalk — перечисляет записи и области в куче.
У каждого процесса имеется минимум одна куча — куча, выделяемая процессу по умолчанию (default process heap). Куча по умолчанию создается в момент запуска процесса и никогда не удаляется в течение срока жизни этого процесса. По умолчанию она имеет размер 1 Мб, но ее начальный размер может быть увеличен, если в файле образа указано иное значение с помощью ключа /HEAP компоновщика. Однако этот объем памяти резервируется только для начала и по мере необходимости автоматически увеличивается (в файле образа можно указать и начальный размер переданной памяти).
Куча по умолчанию может быть явно использована программой или неявно некоторыми внутренними Windows-функциями. Приложение запрашивает память из кучи процесса по умолчанию вызовом Windows-функции GetProcessHeap. Процесс может создавать дополнительные закрытые кучи вызовом HeapCreate. Когда куча больше не нужна, занимаемое ею виртуальное адресное пространство можно освободить, вызвав HeapDestroy. Массив всех куч поддерживается в каждом процессе, и поток может обращаться к ним через Windows-функцию GetProcessHeaps.
Куча может быть создана в больших регионах памяти, зарезервированных через диспетчер памяти с помощью VirtualAlloc или через объекты «файл, проецируемый в память», отображенные на адресное пространство процесса. Последний подход редко применяется на практике, но удобен в случаях, когда содержимое блоков нужно разделять между двумя процессами или между частями компонента, работающими в режиме ядра и в пользовательском режиме. B последнем случае действует ряд ограничений на вызов функций куч. Во-первых, внутренние структуры куч используют указатели и поэтому не допускают перемещения на другие адреса. Во-вторых, функции куч не поддерживают синхронизацию между несколькими процессами или между компонентом ядра и процессом пользовательского режима. Наконец, в случае кучи, разделяемой между кодом пользовательского режима и режима ядра проекция пользовательского режима должна быть только для чтения, чтобы исключить повреждение внутренних структур кучи кодом пользовательского режима.
Как показано на рис. 7–5, диспетчер куч состоит из двух уровней: необязательного интерфейсного (front-end layer) и базового (core heap layer). Последний заключает в себе базовую функциональность, которая обеспечивает управление блоками внутри сегментов, управление сегментами, поддержку политик расширения кучи, передачу и возврат памяти, а также управление большими блоками.
Необязательный интерфейсный уровень (только для куч пользовательского режима) размещается поверх базового уровня. Существует два типа интерфейсных уровней: ассоциативные списки (look-aside lists) и куча с малой фрагментацией (Low Fragmentation Heap, LFH). LFH доступна лишь в Windows XP и более поздних версиях Windows. Единовременно для каждой кучи можно использовать только один интерфейсный уровень.

Диспетчер куч по умолчанию поддерживает параллельный доступ из нескольких потоков. Однако, если процесс является однопоточным или использует внешний механизм синхронизации, он может отключить синхронизацию, поддерживаемую диспетчером куч, и тем самым избежать издержек, связанных с этим видом синхронизации. Для этого при создании кучи или при каждом запросе на выделение памяти такой процесс может указывать флаг HEAP_NO_SERIALIZE.
Процесс также может блокировать всю кучу и запретить другим потокам выполнение операций, требующих согласования состояний между несколькими обращениями к куче. Например, перечисление блоков в куче с помощью Windows-функции HeapWalk требует блокировки кучи, если над ней могут выполняться операции сразу несколькими потоками.
Если синхронизация куч разрешена, для каждой кучи выделяется по одной блокировке, которая защищает все внутренние структуры кучи. B приложениях с большим числом потоков (особенно когда они выполняются в многопроцессорных системах) блокировка кучи может превратиться в точку интенсивной конкуренции. B таком случае производительность можно повысить за счет использования интерфейсного уровня.
Это однонаправленные связанные списки (single linked lists), поддерживающие элементарные операции вроде заталкивания в список или выталкивания из него по принципу «последним пришел, первым вышел» (Last In, First Out, LIFO) без применения блокирующих алгоритмов. Упрощенная версия этих структур данных также доступна Windows-приложениям через функции InterlockedPopEntrySList и InterlockedPushEntrySList. Для каждой кучи создается 128 ассоциативных списков, которые удовлетворяют запросы на выделение блоков памяти размером до 1 Кб на 32-разрядных платформах и до 2 Кб на 64-разрядных.
Ассоциативные списки обеспечивают гораздо более высокую производительность, чем при обычных запросах на выделение памяти, так как несколько потоков могут одновременно выполнять операции выделения и возврата памяти, не требуя применения глобальной для кучи блокировки. Кроме того, благодаря модели размещения LIFO и обращению к меньшему числу внутренних структур данных при каждой операции над кучей оптимизируется локальность кэша.
Диспетчер куч поддерживает ряд блокировок в каждом ассоциативном списке и некоторые счетчики, помогающие независимо регулировать работу с каждым списком. Если поток запрашивает блок такого размера, которого нет в соответствующем ассоциативном списке, диспетчер куч переадресует этот вызов базовому уровню и обновит внутренний счетчик неудачных выделений, значение которого впоследствии будет использовано при принятии решений по оптимизации.
Читать дальшеИнтервал:
Закладка: