The third and last mechanism for manipulating memory is the use of heaps. Heaps are great for allocating lots of small blocks of data. For example, linked lists and trees are best managed using heaps rather than the virtual memory techniques or the memory-mapped file techniques. The advantage of heaps is that they allow you to ignore all the allocation granularity and page boundary stuff and concentrate on the task at hand. The disadvantage of heaps is that allocating and freeing memory blocks is slower than the other mechanisms and you lose the direct control over the committing and decommitting of physical storage.
Internally, a heap is a region of reserved address space. Initially, most of the pages within the reserved region are not committed with physical storage. As you make more allocations from the heap, the heap manager commits more physical storage to the heap. This physical storage is always allocated from the system’s paging file. As you free blocks within a heap, the heap manager decommits the physical storage.
When a process initializes, the system creates a heap in the process’ address space. This heap is called the process’ default heap. By default, this heap’s region of address space is 1 MB in size. However, the system can grow a process’ default heap so that it becomes larger than this. You can change the default region size of 1 MB using the /HEAP linker switch when you create an application. Because a dynamic-link library (DLL) does not have a heap associated with it, you should not use the /HEAP switch when you are linking a DLL. The /HEAP switch has the following syntax:
Many Windows functions require the process’ default heap. For example, the core functions in Windows perform all of their operations using Unicode characters and strings. If you call an ANSI version of a Windows function, this ANSI version must convert the ANSI strings to Unicode strings and then call the Unicode version of the same function. To convert the strings, the ANSI function needs to allocate a block of memory to hold the Unicode version of the string. This block of memory is allocated from your process’ default heap. Many other Windows functions require the use of temporary memory blocks; these blocks are allocated from the process’ default heap. Also, the old 16-bit Windows functions LocalAlloc and GlobalAlloc make their memory allocations from the process’ default heap
Because the process’ default heap is used by many of the Windows functions, and because your application has many threads simultaneously calling the various Windows functions, access to the default heap is serialized. In other words, the system guarantees that only one thread at a time can allocate or free blocks of memory in the default heap at any given time. If two threads attempt to simultaneously allocate a block of memory in the default heap, only one thread will be able to allocate a block; the other thread will be forced to wait until the first thread’s block is allocated. Once the first thread’s block is allocated, the heap functions will allow the second thread to allocate a block. This serialized access causes a small performance hit. If your application has only one thread and you want to have the fastest possible access to a heap, you should create your own separate heap and not use the process’ default heap. Unfortunately, you cannot tell the Windows functions not to use the default heap, so their accesses to the heap are always serialized.
Reasons for creating new process heap:
- Component protection.
- More efficient memory management (avoiding fragmentation)
- Local access.
- Avoid thread synchronization overhead.
- Quick free.
It is recommended that you use VirtualAlloc when allocating large blocks (around 1 MB or more). Avoid using the heap functions for such large allocations.