Today's post is actually the result of a recent series of questions on Heap and the Heap Manager that I fumbled quite hopelessly! Once I got back to my desk, I pulled out my trusty copy of Windows Internals and started reading. The more I read, the more I thought about a blog post. The catalyst for inspiration stems from all sorts of sources - in this case I'm thankful to an engineer who simply wouldn't let me off the hook! So let's get started ...
First, what exactly is heap? Heap is an area of memory reserved for data that is created when a program is executed. Each process has a process heap that is created when the process is started, and is never deleted so long as the process is running. By default, this heap is 1MB in size. This is just an initial reservation though - as more is needed, the heap will expand. You can also specify a larger starting size in the image file by using the /HEAP linker flag. The default heap can be explicitly used by the program or implicitly used by some Windows internal functions.
Simply put, the default heap spans a range of addresses. Some of these ranges are reserved, some ranges are committed and have pages of memory associated with them. In this instance, the addresses are contiguous. If the default heap needs to allocate more memory than it has available in its current reserved address space, the heap can either fail the call requesting the memory, or reserve an additional range elsewhere in the process. By default, the heap manager will attempt to perform the second operation. When the default heap needs more memory than is currently available, it reserves another 1MB address range within the process. In addition, it also performs an initial commit of the memory needed from this reserved range to satisfy the allocation request. The heap manager then becomes responsible for managing this new memory region as well as the original heap space.
Processes can also create a private heap - a block of one or more pages in the address space of the calling process. The process can then manage the memory in that heap. There is no difference between the memory allocated from a private heap and that allocated by using the other memory allocation functions. When creating this private heap object, you can specify both the initial size and maximum size for the heap. It is important to remember that the memory of a private heap object is only accessible to the process that created it. If a DLL creates a private heap, it does so in the address space of the process that called the DLL. It is only accessible to that process. When a process no longer needs a private heap, it can recover the virtual address space. Within each process there is an array that maintains a list of all heaps.
Before wrapping up, let's quickly look at the Heap Manager itself. Many applications allocate smaller blocks than the 64kb minimum allocation granularity possible. Allocating such a large area for relatively small allocations is hardly optimal from a memory usage or performance standpoint. To address this, Windows uses the heap manager to manage allocations inside larger memory areas. The allocation granularity in the heap manager is relatively small. On 32-bit systems, this value is 8 bytes, and 16 bytes on 64-bit systems. The heap manager itself is structured in two layers - a front-end layer (which is optional), and the core heap. The core heap is responsible for the basic functionality and is mostly common across the user and kernel mode heap implementations. For user mode heaps only, an optional front-end heap layer can exist on top of the existing core functionality. There are two types of front-end layers: look-aside lists and the Low Fragmentation Heap (aka LFH which is available in Windows XP and later operating systems). Only one front-end layer can be used for one heap at a time. We'll discuss both of these in our next post on Heap.
OK - that will do it for Part One of our look at Heap. In our next Heap post, we'll cover Look-Aside lists and Heap Fragmentation among other things.