Daily Archives: February 20, 2006

A Debugging Exercise

A few weeks ago I had an interesting debugging problem. A program we develop had a memory leak in it that Visual Studio was catching when it ended. The trace text was something like this:

Detected memory leaks!
Dumping objects ->
{292300} normal block at 0x05590040, 2771928 bytes long.
Data: <> FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF FF 00
{292294} normal block at 0x05110040, 2613312 bytes long.
Data: <> FF FF FF 00 FF FF FF 00 FF FF FF 00 FF FF FF 00

Visual Studio 2003 is often pretty good at telling you where a memory leak occured, giving you a source code file and line number of where the memory allocation originated. In the case above, I don’t have that. There are two relatively easy ways of solving this.

The first method is to examine the data that isn’t being freed. In this case, I have two large objects of about 2.5 MB each. That’s pretty big–there aren’t too many (if any) individual objects in the software that are that large. So it could be an array. The data begins with a repeated pattern {FF FF FF 00}. Definitely looks like an array of 4-byte segments. Applying a little knowledge of the application itself–it displays large bitmaps–and we realize that the memory comes from an array of RGB values.

Another way to investigate this is to set a breakpoint on the memory allocation that isn’t being freed. The number in braces {292300} is the memory allocation number in debug mode in Visual C++. In order for this technique to work, you must first ensure that the number is the same each time. In my case, the memory leak would happen if I just opened and closed the program (because an image is always being drawn) without doing anything else.

First, set a breakpoint at the beginning of the program (or any place definitely before the memory leak). Start the program and when it breaks, enter the following into the watch window:

{,,msvcr71d.dll}_crtBreakAlloc

And for the value enter 292300.

If you continue the execution, the program will break on the 292,300th memory allocation. It will stop in the memory allocator, and you can then look at your stack frame and see exactly where the memory allocation is taking place.

MSDN has a great article about this.

In my problem it was for a set of memory blocks being used as working space for resizing and smoothing bitmaps. They were allocated once during execution and thus did not really provide a long-term threat. This leads to a possible third solution:

Ignore. All memory is reclaimed once the program exits. Nobody would ever do that, though…. would they?

…of course not…