Управление памятью кучи
Выделение блоков памяти из кучи осуществляется путем указания
дескриптора кучи, размера блока и нескольких флагов.
LPVOID HeapAlloc ( HANDLE hHeap, DWORD dwFlags, SIZE_T
dwBytes)
Возвращаемое значение: указатель на выделенный блок памяти или NULL
при неудаче (кроме случаев,- когда задано генерирование исключений).
Параметры функции HeapAlloc
hHeap — дескриптор кучи, из которой должен быть выделен блок памяти.
Этот дескриптор должен быть получен функциями GetProcessHeap или
HeapCreate.
dwFlags представляет собой комбинацию трех флагов.
• HEAP_GENERATE_EXCEPTIONS И HEAP_NO_SERIALIZE имеют то же
значение, что и для функции HeapCreate. Первый флаг можно не указывать,
если он был установлен функцией HeapCreate для данной кучи. Второй флаг
используется при выделении памяти из кучи процесса.
• HEAP_ZERO_MEMORY указывает на то, что выделенная память будет
заполнена нулями; в противном случае содержимое памяти будет
неопределенным.
dwBytes — размер блока памяти, который должен быть выделен. Для
невозрастающих куч его предел составляет 0x7FFF8 (примерно 0,5 Мбайт).
Освобождение памяти из кучи выполняется элементарно.
BOOL HeapFree ( HANDLE hHeap, DWORD dwFlags,
LPVOID lpMem)
dwFlags должен быть равен нулю или константе HEAP_NO_SERIALIZE.
lpMem должен иметь значение, возвращенное функцией HeapAlloc или
HeapReAlloc,
а hHeap — это дескриптор кучи, из которой был выделен блок lpMem.
Для изменения размера блоки памяти могут быть выделены заново.
LPVOID HeapReAlloc ( HANDLE hHeap, DWORD dwFlags,
LPVOID lpMem, SIZE_T dwBytes)
Возвращаемое значение: указатель на выделенный заново блок. При неудаче возвращает NULL или вызывает исключение.
Параметры функции HeapReAlloc
Первый параметр hHeap упоминался выше. dwFlags указывает некоторые
важные управляющие флаги.
• HEAP_GENERATE_EXCEPTIONS и HEAP_NO_SERIAL_S1ZE, как
в предыдущих случаях.
• HEAP_ZERO_MEMORY — инициализируется только заново выделяемая
память (когда значение dwByte больше размера исходного блока).
Содержимое исходного блока не изменяется.
• HEAP_REALLOC_IN_PLACE_ONLY указывает на то, что блок не может
быть перемешен. При увеличении размера блока память должна выделяться по адресу, следующему сразу после существующего блока.
lpMem указывает на существующий блок в куче hHeap, который должен
быть выделен заново.
dwBytes — новый размер блока, который может быть больше или меньше
текущего.
Обычно возвращаемый указатель — тот же, что и значение lpMem. Если же
блок был перемещен (это разрешается, когда флаг
HEAP_REALLOC_IN_PLACE_ONLY опущен), то возвращенное значение
будет другим. Следите за обновлением всех ссылок на блок.
Размер выделенного блока определяется функцией НеарSize (на самом деле
имя этой функции должно быть BlockSize, так как она относится к блоку, а не к куче) с указанием дескриптора кучи и указателя на блок.
DWORD HeapSize ( HANDLE hHeap, DWORD dwFlags,
LPCVOID lpMem)
Возвращаемое значение: размер блока или нуль при неудаче.
Флаг HEAP_NO_SER IALIZE
В функциях HeapCreate, HeapAlloc и HeapReAlloc может быть указан
флаг HEAP_NO_SERIALIZE. Его применение позволяет получить небольшой
прирост быстродействия, производительности, так как функции не
предоставляют потокам взаимные исключения при доступе к куче. Применение
этого флага безопасно в немногих описанных ниже ситуациях.
• Программа не использует потоки, или, точнее, процесс имеет только один
поток.
• Каждый поток имеет собственную кучу или группу куч, к которым не
обращаются другие потоки.
• Программа имеет собственный механизм взаимных исключений для
предотвращения одновременного доступа к куче нескольких потоков, исполь-
зующих функции HeapAlloc и HeapReAlloc. Для тех же целей в Windows
2000/NT доступны функции HeapLock и HeapUnlock.
Флаг HEAP_GENERATE__EXCEPTIONS
Вызов исключений в случае неудачного выделения памяти делает
ненужными раздражающие проверки ошибок после каждого выделения. Более
того, исключение или обработчик завершения может очистить память, которая
была выделена. Возможны два кода исключения.
1. STATUS_NO_MEMORY указывает на то, что система не может создать блок
заданного размера. Причиной может быть фрагментация памяти, невозраста-
ющая куча, которая достигла своего предела, или даже исчерпание всей памяти возрастающими кучами.
2. STATUS_ACCESS_VIOLATION указывает на то, что куча была повреждена.
Например, программа могла произвести запись в память за границами выделен-
ного блока.
Другие функции для работы с кучей
Функция HeapCompact делает попытку объединения, или дефрагментации,
смежных свободных блоков в куче; HeapValidate пробует определить
повреждение кучи; HeapWalk перебирает блоки в куче, а GetProcessHeap
получает все дескрипторы кучи, действительные для данного процесса.
Функции HeapLock и HeapUnlock позволяют потоку упорядочить доступ
к куче.
Резюме по управлению кучей
Обычная последовательность действий при работе с кучей такова.
1. Получить дескриптор кучи с помощью функций CreateHeap или
GetProcessHeap
2. Выделить блоки в куче, используя HeapAlloc.
3. По необходимости освободить все или некоторые блоки функцией
HeapFree.
4. Уничтожить кучу и закрыть дескриптор функцией HeapDestroy.