Особенности кучи в Windows 95, Windows NT.
1. В Windows максимальный размер кучи может быть практически равен размеру свободного адресного пространства. По умолчанию выделяется 1 Мб и передаются 2 страницы физической памяти.
2. В Windows поддерживается несколько куч.
3. Кучи Win32 могут расти за пределы первоначально отведенного для них размера. В этом случае kernel32 выделяет дополнительный блок линейного адресного пространства и связывает с ним кучу, то есть образует подкучу.
Каждая куча Win32 поддерживает 4 отдельных списка свободных блоков, чтобы избежать чрезмерной фрагментации.
4. При создании любого процесса ОС автоматически создаёт кучу, которая называется куча, предоставляемая процессу по умолчанию. Куча нужна самой ОС для выполнения функций Win32.
Пример. UNICODE2-х байтная ANSI привычная.
Windows NT, 2000 работают только с UNICODE, поэтому когда вызывается ANSI вариант, то для выполнения этой функции необходимо организовать буфер для перевода ANSI в UNICODE.
HeapCreate куча 3 |
GetProcessHeap куча 1 |
Process Data Base |
HeapCreate куча 2 |
подкучи
U DVodJq5HYu/DeasjS19L4/WJy20nr5NkKq1uiT80usfHBqvP7WAVbFaLZfa6HMbKvz+l693L6vkt ZEpdXowP9yAijvEvDD/4jA4lMx3cQCaITsFNkqUcVTCdgWD/Vx/4uL0DWRby/4DyGwAA//8DAFBL AQItABQABgAIAAAAIQC2gziS/gAAAOEBAAATAAAAAAAAAAAAAAAAAAAAAABbQ29udGVudF9UeXBl c10ueG1sUEsBAi0AFAAGAAgAAAAhADj9If/WAAAAlAEAAAsAAAAAAAAAAAAAAAAALwEAAF9yZWxz Ly5yZWxzUEsBAi0AFAAGAAgAAAAhAMihT+xjAgAAfQQAAA4AAAAAAAAAAAAAAAAALgIAAGRycy9l Mm9Eb2MueG1sUEsBAi0AFAAGAAgAAAAhAK5ceKDeAAAACAEAAA8AAAAAAAAAAAAAAAAAvQQAAGRy cy9kb3ducmV2LnhtbFBLBQYAAAAABAAEAPMAAADIBQAAAAA= " o:allowincell="f"> подкучи
У нас куча 1 создана по умолчанию, а 2 и 3 – это дополнительные кучи, создаваемые процессом. PDB – эта таблица содержит указатели на кучи. ToolHelp – специальный набор функций.
Структура кучи. Список(Заголовок и арена) кучи Win32.
… 2 блок 2 арена 1 блок 1 арена … критическая секция массив из 4-х заголовков размер |
заголовок кучи
Каждый блок имеет свой заголовок – арену. Заголовок кучи имеет следующую структуру. Заголовок состоит из полей.
1. общий размер памяти, зарезервированной для кучи.
2. указатель на следующую кучу, если она есть.
3. указатель на начало списка дополнительных подкуч данной кучи.
4. списки свободных блоков.
Для снижения фрагментации памяти и ускорения поиска свободных блоков заголовок каждой кучи содержит 4 списка свободных блоков:
1-ый список состоит из блоков, размер которых меньше 20h байт.
2-ой список состоит из блоков, размер которых меньше 80h байт.
3-ий список состоит из блоков, размер которых меньше 200h байт.
4-ый список состоит из блоков, размер которых меньше FFFFFFFFh байт.
Kernel32 ищет свободный блок в наиболее подходящем блоке.
Список свободных блоков
куча заголовок |
//////////////////////////// |
Каждая структура списка свободных блоков имеет следующий формат.
- максимальный размер блока (это число 20h, 80h, 200h и FFFFFFFFh).
- структура, представляющая собой арену, то есть заголовок.
Длина блока в арене 0, а указатель типа next указывает на первый свободный блок данного размера в куче, то есть указывает на первый свободный блок.
В заголовке кучи кроме того находится указатель на следующую кучу, созданную функцией HeapCreate(…). Если следующей кучи нет, то 0. В заголовке кучи имеется поле флагов.
В заголовке содержится критическая секция CriticalSection. Это структура, которая организует последовательный доступ к куче различных потоков процесса.
Несколько потоков обращаются к куче для того, чтобы выделить блок памяти в куче. Процесс выделения памяти в куче состоит из следующих этапов.
1. Поиск свободного блока.
2. Выделение физической памяти для этого блока.
3. Запись информации в выделенный блок.
Первый поток выполнил два этапа, его квант времени истёк. Начинается выполнение программного кода второго потока. Второй поток выполняет три этапа и находит тот же блок. Когда управление вернётся к первому потоку, то он запишет информацию в тот же блок, то есть информация второго потока будет испорчена.
Чтобы этого избежать существует критическая секция. Это признак. Как только какой-либо поток начинает работу с кучей устанавливается признак в CriticalSection.
Недостатком кучи является снижение производительности из-за последовательного доступа.
Heap_No_Serialsize – куча допускает одновременный доступ к куче со стороны нескольких потоков. Его рекомендуется не использовать, а если использовать, то только в том случае, если процесс имеет один поток.
В заголовке кучи обычно указывается сигнатура “HI” – признак того, что это заголовок кучи. Рассмотрим структуру отдельных блоков кучи. Каждый блок начинается с заголовка, то есть с арены.
Структура арены.
Арена в занятых блоках. Начинается с поля длины блока. Затем в некоторых версиях Windows кроме длины блока могут указываться значения счётчика команд перед обращением к куче.
Арена в свободных блоках. SIZE – размер PREV – указатель на пустой свободный блок. NEXT – указатель на следующий свободный блок, то есть свободные блоки связаны в цепочки.
Функции управления кучей Win32.
GetProcessHeap(…) – получить дескриптор кучи, предоставляемый процессу по умолчанию. Эта функция находит PDB и извлекает из базы данных дескриптор кучи.
HeapCreate(…) – создание кучи. Вызывают не только приложения пользователя, но и kernel32.dll и user32.dll вызывает для создания системных структур данных, например PDB или базы данных потока (TDB).
Процесс создания кучи проходит в 2 этапа:
1. резервирование памяти для кучи и связывание кучи в списке куч процесса.
2. инициализация всех полей заголовка кучи.
Функция HeapCreate(…) проверяет корректность параметров. Округляет границу кучи до ближайшего целого числа кратного 4 Кб.
Удаление кучи.
HeapDestroy(…). Проблема состоит в том, что 1.куча должна быть свободной, то есть CriticalSection=0. 2. куча может иметь подкучи.
Необходимо удалить весь список связанных подкуч. Windows поддерживает связанный список кучи, то есть HeapDestroy(…) должна выполнять действия по корректировке списка.