Харт Джонсон М.
Шрифт:
Для освобождения блока памяти, распределенного из кучи достаточно вызвать следующую функцию:
dwFlags — значениями этого параметра должны быть 0 или HEAP_NO_SERIALIZE. Значением параметра lpMem должно быть значение, возвращенное функциями HeapAlloc или HeapReAlloc (описана ниже), а дескриптор hHeap должен быть дескриптором кучи, которой принадлежит освобождаемый блок памяти, указываемый lpMem.
Для повторного распределения блоков памяти с целью изменения их размера используется следующая функция:
Возвращаемое значение: в случае успешного выполнения — указатель на перераспределенный блок памяти; в противном случае функция возвращает NULL или вызывает исключение.
• HEAP_GENERATE_EXCEPTIONS и HEAP_NO_SERIALIZE: это те же флаги, которые были описаны при рассмотрении функции HeapAlloc.
• HEAP_ZERO_MEMORY: нулями инициализируется лишь вновь распределенная память (когда значение параметра dwBytes превышает первоначальный размер блока). Содержимое исходного блока не изменяется.
• HEAP_REALLOC_IN_PLACE_ONLY: установка этого флага запрещает перемещение блока при перераспределении памяти. Если вы увеличиваете размер блока, адреса добавляемой памяти будут располагаться непосредственно вслед за адресами памяти, занимаемой существующим блоком.
lpMem — указывает на блок памяти, перераспределяемый из кучи hHeap.
dwBytes — размер нового блока памяти, который может быть как меньше, так и больше размера существующего блока.
Обычно возвращенный указатель имеет то же значение, что и указатель lpMem. В то же время, если блок перемещается (чтобы такое перемещение было разрешено, следует при вызове функции опустить флаг HEAP_REALLOC_IN_PLACE_ONLY), то возвращенное значение будет другим. Следите за своевременным изменением любых ссылок на блок. Независимо от того, перемещается блок или не перемещается, содержащиеся в нем данные остаются неизменными; в то же время, при уменьшении блока часть данных может теряться.
Размер распределенного блока памяти можно определить, вызвав функцию HeapSize (эту функцию следовало бы назвать BlockSize, поскольку о размере кучи она ничего не сообщает), используя в качестве параметров дескриптор кучи и указатель на блок.
Возвращаемое значение: в случае успешного выполнения — размер блока; иначе — ноль.
При вызове функций HeapCreate, HeapAlloc и HeapReAlloc можно указывать флаг HEAP_NO_SERIALIZE. Использование этого флага иногда обеспечивает незначительный выигрыш в производительности, поскольку во время обращения функции к куче взаимоисключающая блокировка к потокам в этом случае применяться не будет. Результаты простых тестов, в которых не делалось ничего, кроме распределения блоков памяти, показали повышение производительности примерно на 16 процентов. Этот флаг без какого бы то ни было риска можно использовать в следующих ситуациях:
• Программа не использует потоки (глава 7), или, точнее, процесс (глава 6) имеет только один поток. В данной главе этот флаг используется во всех примерах.
• Каждый поток имеет собственную кучу или набор куч, и никакой другой поток не имеет доступа к этой куче.
• Программа располагает собственным механизмом взаимоисключающей блокировки, который предотвращает одновременный доступ к куче сразу нескольких потоков, использующих функции HeapAlloc и HeapAlloc. Для этой цели также могут применяться функции HeapLock и HeapUnlock.
Разрешение исключений вместо возврата значений NULL в случае сбоев при распределении памяти позволяет избавиться от утомительной необходимости тестирования результатов каждой попытки такого распределения. К тому же, обработчики исключений или завершения могут производить очистку памяти, которая к этому моменту была частично распределена. Эта методика применена в нескольких примерах.
Возможны два кода исключения: