Managing Heap Memory
Obtain memory blocks from a heap by specifying the heap''s handle, the block size, and several flags.
Return: A pointer to the allocated memory block, or NULL on failure (unless exception generation is specified).
LPVOID HeapAlloc (
HANDLE hHeap,
DWORD dwFlags,
SIZE_T dwBytes)
Parameters
hHeap is the handle of the heap in which the memory block is to be allocated. This handle should come from either GetProcessHeap or HeapCreate.dwFlags is a combination of three flags.
- HEAP_GENERATE_EXCEPTIONS and HEAP_NO_SERIALIZE
These flags have the same meaning as for HeapCreate. The first flag is ignored if it was set with the heap''s HeapCreate function and enables exceptions for the specific HeapAlloc call, even if HEAP_GENERATE_EXCEPTIONS was not specified by HeapCreate. The second should not be used when allocating within the process heap. - HEAP_ZERO_MEMORY
This flag specifies that the allocated memory will be initialized to 0; otherwise, the memory contents are not specified.
dwBytes is the size of the block of memory to allocate. For nongrowable heaps, this is limited to 0x7FFF8 (approximately 0.5MB).Note:
Once HeapAlloc returns a pointer, use the pointer in the normal way; there is no need to make reference to its heap. Notice, too, that the LPVOID data type represents either a 32-bit or 64-bit pointer.Deallocating memory from a heap is simple.
BOOL HeapFree (
HANDLE hHeap,
DWORD dwFlags,
LPVOID lpMem)
dwFlags should be 0 or HEAP_NO_SERIALIZE. lpMem should be a value returned by HeapAlloc or HeapReAlloc (described next), and, of course, hHeap should be the heap from which lpMem was allocated.Memory blocks can be reallocated to change their size.
Return: A pointer to the reallocated block. Failure returns NULL or causes an exception.
LPVOID HeapReAlloc (
HANDLE hHeap,
DWORD dwFlags,
LPVOID lpMem,
SIZE_T dwBytes)
Parameters
The first parameter, hHeap, is the same heap used with the HeapAlloc call that returned the lpMem value (the third parameter). dwFlags specifies some essential control options.
- HEAP_GENERATE_EXCEPTIONS and HEAP_NO_SERIALIZE
These flags are the same as described for HeapAlloc. - HEAP_ZERO_MEMORY
Only newly allocated memory (when dwBytes is larger than the original block) is initialized. The original block contents are not modified. - HEAP_REALLOC_IN_PLACE_ONLY
This flag specifies that the block cannot be moved. When you''re increasing a block''s size, the new memory must be allocated at the address immediately after the existing block.
lpMem specifies the existing block in hHeap to be reallocated.dwBytes is the new block size, which can be larger or smaller than the existing size.Normally, the returned pointer is the same as lpMem. If, on the other hand, a block is moved (permit this by omitting the HEAP_REALLOC_IN_PLACE_ONLY flag), the returned value will be different. Be careful to update any references to the block. The data in the block is unchanged, regardless of whether or not it is moved; however, some data will be lost if the block size is reduced.Determine the size of an allocated block by calling HeapSize (this function should have been named BlockSize because it does not obtain the size of the heap) with the heap handle and block pointer.
Return: The size of the block, or zero on failure.
DWORD HeapSize (
HANDLE hHeap,
DWORD dwFlags,
LPCVOID lpMem)
The HEAP_NO_SERIALIZE Flag
The functions HeapCreate, HeapAlloc, and HeapReAlloc can specify the HEAP_NO_SERIALIZE flag. There can be a small performance gain with this flag because the functions do not provide mutual exclusion to threads accessing the heap. Some simple tests that do nothing except allocate memory blocks measured a performance improvement of about 16 percent. This flag is safe in a few situations, such as the following.
- The program does not use threads (Chapter 7), or, more accurately, the process (Chapter 6) has only a single thread. All examples in this chapter use the flag.
- Each thread has its own heap or set of heaps, and no other thread accesses the heap.
- The program has its own mutual exclusion mechanism (Chapter 8) to prevent concurrent access to a heap by several threads using HeapAlloc and HeapReAlloc. HeapLock and HeapUnlock are also available for this purpose.
The HEAP_GENERATE_EXCEPTIONS Flag
Forcing exceptions in the case of memory allocation failure avoids the need for annoying error tests after each allocation. Furthermore, the exception or termination handler can clean up memory that did get allocated. This technique is used in some examples.Two exception codes are possible.
- STATUS_NO_MEMORY indicates that the system could not create a block of the requested size. Causes can include fragmented memory, a nongrowable heap that has reached its limit, or even exhaustion of all memory with growable heaps.
- STATUS_ACCESS_VIOLATION indicates that the specified heap has been corrupted. For example, a program may have written memory beyond the bounds of an allocated block.
Other Heap Functions
HeapCompact attempts to consolidate, or defragment, adjacent free blocks in a heap. HeapValidate attempts to detect heap corruption. HeapWalk enumerates the blocks in a heap, and GetProcessHeaps obtains all the heap handles that are valid in a process.Chapter 8.Note that these functions do not work under Windows 9x or CE. Also, some obsolete functions, such as GlobalAlloc and LocalAlloc, were used for compatibility with 16-bit systems. These functions are mentioned simply as a reminder that many functions continue to be supported even though they are no longer relevant.
Summary: Heap Management
The normal process for using heaps is straightforward.
- Get a heap handle with either CreateHeap or GetProcessHeap.
- Allocate blocks within the heap using HeapAlloc.
- Optionally, free some or all of the individual blocks with HeapFree.
- Destroy the heap and close the handle with HeapDestroy.
Figure 5-2. Memory Management in Multiple Heaps
[View full size image]

