Search code examples
visual-c++memory-leakscrtdbg.h

How to trace the source of a CRT debug memory leak output from managed C# code?


I'm running a software written in C# (WPF) that uses a lot of native legacy code. When I close the software, the debugger keeps running and my debug output screen prints this:

Detected memory leaks!
Dumping objects ->
{41198} normal block at 0x00000211F11C58F0, 16 bytes long.
 Data: <                > D8 CE DF B0 8D 00 00 00 00 00 00 00 00 00 00 00 
{41194} normal block at 0x00000211C66AD710, 96 bytes long.
 Data: <D:\mydir\somedir> 44 3A 5C 72 65 70 6F 5C 69 71 73 2D 74 72 75 6E 
{41193} normal block at 0x00000211F11C5210, 16 bytes long.
 Data: <                > 80 83 A1 E1 11 02 00 00 00 00 00 00 00 00 00 00 
{41192} normal block at 0x00000211E1A18360, 88 bytes long.
 Data: <                > 90 80 9D E0 11 02 00 00 90 80 9D E0 11 02 00 00 
(Repeated)

(I changed the path that shows there to "mydir\somedir")

The messages just keep coming for probably more than a minute until I shut it down from the "Stop Debugging" button.

The software is using many libraries written in C and C++. There are several C++/CLI projects that perform as wrappers and used by the C# code.

I do have access to the native source code that's being used so I ran a search for all the definitions of _CRTDBG_MAP_ALLOC and re-defined the new operator as explained in MSDN, but the output remained the same and did not show line/file info whatsoever. I'm not even sure that it's coming from our code.

How can I trace the source of this memory leak? Is there a way to at least identify what file/project is causing this? Assuming this is coming from our code, is there any way to use the C++/CLI code to debug this?


Solution

  • The problem was actually in the C++/CLI wrappers.

    All the code that's responsible for freeing memory was written in the destructors of the classes, assuming that they will be called automatically by the garbage collector.

    However, it turns out that the GC does not invoke the destructor, rather it calls the finalizer.

    The solution was to move all the code from destructors to finalizers, and after that not a single dump line is shown in the debug output when I close the program and memory is freed when the GC runs and the class is considered dead.