Monday, July 27, 2009

Using Windows multiple memory heaps for finding leaks

If you, like me (but sometimes I feel it's just me left) use C and the Win32/Win64 API for Windows programming, you might be interested in this little trick which I use quite often on Windows to make sure I do not have any memory leaks.

Usually, you allocate from the heap using something like malloc for a level of portability, as the Windows HeapXxx calls are Windows specific, and malloc maps to these guys anyway. usually.

In Windows, each process has a default heap. In most cases, DLL data is private, but heap allocations are usually done from the Process heap. This causes a memory allocation issue that is all too common: There may be a memory leak, and again, it may not be, as everyone is allocating data from the same heap, including any libraries, static or dynamic, that you may use, when all you want to know is if you have a leak in your code.

And this what you can do here: Although a process has a default heap, there is no stopping it having several heaps. The memory allocations functions that you mostly use on Win32, like HeapAlloc and HeapFree, take a handle to the heap to allocate from as the first parameter, and this handle can come from two places:
  • GetProcessHeap() - Get the default heap for the process.
  • HeapCreate() - Create a new heap.
Often, you see code like this then:
LPTSTR pStr;
if((pStr = HeapAlloc(GetProcessHeap(), 0, nLen)) == NULL)
return NULL;
and so on. Not too exciting stuff. Instead, I recommend you keeping a global handle for the heap to use for all you allocations, and use this handle, like this:
HANDLE g_hHeap;
winMain()
...
g_hHeap = GetProcessHeap();
...
LPTSTR SomeFunction()
{
LPTSTR pStr;

if((pStr = HeapAlloc(g_hHeap, 0, nLen)) == NULL)
return NULL;
...
}
This looks like it is the same thing, but it does give you one advantage: You can, when you set your heap to the return value from GetProcessHeap() instead create your own heap, using HeapCreate(), and you need only do this in one place. And using some other nifty calls, you can "walk" this heap, and see how many allocations you have and how big they are. And that is from your heap only! No external DLLs, no nothing but what you have allocated! If you allocate 15 bytes, you will see 15 more bytes allocated from your heap, no more and no less. How can you do this then? The way I do this, if this is a GUI application, I provide a menu option with a dialog that shows me the # of allocated blocks and the size and stuff like that (also, I do thisin such a way, susally, so I can ifdef this menu option away if I want to). So how do you "walk" a heap then? Oh, that's easy, here is a simple sample for you:
PROCESS_HEAP_ENTRY entry;
unsigned int nBlocks;
unsigned int nFreeBlocks;
unsigned int nSize;

...
entry.lpData = NULL;
nBlocks = nFreeBlocks = 0;
nSize = 0;

/* Walk the heap and get info. */
while(HeapWalk(g_hHeap, &entry) != 0)
{
if(entry.wFlags == 0)
{
nFreeBlocks++;
continue;
}
nBlocks++;
nSize += entry.cbData;
}

I find this really useful, and it allows me to easily track down those small leaks (as I know the size AND count, this is much easier), that can, in a production system, end up being major leaks and cause big issues.

/Karlsson

No comments: