Thursday, November 12, 2009

Managing Heap Memory









Managing Heap Memory


Obtain memory blocks from a heap by specifying the heap's handle, the block size, and several flags.



LPVOID HeapAlloc (
HANDLE hHeap,
DWORD dwFlags,
SIZE_T dwBytes)

Return: A pointer to the allocated memory block, or NULL on failure (unless exception generation is specified).

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.



LPVOID HeapReAlloc (
HANDLE hHeap,
DWORD dwFlags,
LPVOID lpMem,
SIZE_T dwBytes)

Return: A pointer to the reallocated block. Failure returns NULL or causes an exception.

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.



DWORD HeapSize (
HANDLE hHeap,
DWORD dwFlags,
LPCVOID lpMem)

Return: The size of the block, or zero on failure.

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.


  1. 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.

  2. 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.


HeapLock and HeapUnlock allow a thread to serialize heap access, as described in 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.


  1. Get a heap handle with either CreateHeap or GetProcessHeap.

  2. Allocate blocks within the heap using HeapAlloc.

  3. Optionally, free some or all of the individual blocks with HeapFree.

  4. Destroy the heap and close the handle with HeapDestroy.


This process is illustrated in both Figure 5-2 and Program 5-1.


Figure 5-2. Memory Management in Multiple Heaps

[View full size image]




Normally, programmers use the C library <stdlib.h> memory management functions and can continue to do so if separate heaps or exception generation are not needed. malloc is then equivalent to HeapAlloc using the process heap, realloc to HeapReAlloc, and free to HeapFree. calloc allocates and initializes objects, and HeapAlloc can easily emulate this behavior. There is no C library equivalent to HeapSize.










    No comments:

    Post a Comment