jComHeap : checks the COM heap for leaks using IMallocSpy

Download Files

Changes

  1. Initial Version

Installation

None.

Notes

Use jComHeap to discover COM heap leaks. For an example of how to use it see testjComHeap.cpp.

Sample Output

If you have the registry entry HKEY_LOCAL_MACHINE\SOFTWARE\arrizza\Debug\jComHeap (see debug.reg) set to "1" and you run testjComHeap, you will see something like the following:

d:\projects\src\jcomheap_test\testjcomheap.cpp(105) : jComHeap: no leaks found.
d:\projects\src\jcomheap_test\testjcomheap.cpp(77) : jComHeap: no leaks found.
d:\projects\src\jcomheap_test\testjcomheap.cpp(47) : jComHeap: no leaks found.
d:\projects\src\jcomheap_test\testjcomheap.cpp(132) : jComHeap: no leaks found.
d:\projects\src\jcomheap_test\testjcomheap.cpp(20) : jComHeap: no leaks found.
d:\projects\src\jcomheap_test\testjcomheap.cpp(146) : jComHeap: LEAKS! Allocs=4 Frees=3 Unfreed=48 bytes in 1 blocks
-----  alloc: {     4} 0X0013A3A8 size=48     bytes numallocs=1 numfrees=0
-----    as Data: 2A 00 00 00 74 00 65 00 64 00 00 00 00 00 00 00 00 00 00 00 C3 6A 41 00 8D 69 41 00 7C 6B
-----    as bstr: len=42   bytes <tedAA|AhA*A#A>
jComHeap: Report -------- Done
The first 5 runs show that there were no leaks. The filename and line numbers are for the line where the Report() call is done.

The 6th run shows that a leak was found. Specifically there were 48 bytes leaked in 1 allocation (a "block").

The memory block was the 4th allocation as indicated by the "alloc { 4}". The address of the memory was 0x0013A4A8.

The size allocated was 48 bytes. This is probably not the size you requested. COM allocations are rounded up to the next 16 byte boundary (i.e. a "paragraph").

Memory can be reused. This particular memory block was allocated once and not freed (thus the leak).

The "as Data:" line shows the first 30 or so chars as hex digits.

The "as bstr:" line shows the same chars as UNICODE chars in case the memory was a BSTR. In this case, it was a bstr and the first few chars are "ted" which is the BSTR that was leaked.

Verbose output

Setting the jcomheap registry entry to "2" will give you a full pattern of allocations and frees. The following shows the first run from testjcomheap:

jComHeap:: Alloc  {     1} succeeded at 0X0013A928,   216 bytes
jComHeap:: Alloc  {     2} succeeded at 0X0013AFB0,    16 bytes
jComHeap:: Alloc  {     3} succeeded at 0X0013AA20,    16 bytes
jComHeap:: Free   {     2} succeeded at 0X0013AFB0,    16 bytes
jComHeap:: Free   {     3} succeeded at 0X0013AA20,    16 bytes
jComHeap:: Free   {     1} succeeded at 0X0013A928,   216 bytes
d:\projects\src\jcomheap_test\testjcomheap.cpp(105) : jComHeap: no leaks found.

The 216 bytes and the 16 bytes (alloc #2) are from internal allocations done by the CoInitialize().

IMallocSpy and MSXML

There is a problem with using IMallocSpy with MSXML. MSXML allocates memory and retains a reference to it even after a CoUninitialize(). The memory is released at DLL unload time, i.e. at ProcessDetach. The problem is that by that time, the object implementing IMallocSpy, in this case jComHeap, has been deallocated. Ole32 is trying to call the IMallocSpy PreFree and PostFree methods which cause an exception to be thrown.

Here is a sample piece of code that causes the exception to be thrown:

  CoInitialize(0);
    {
    IXMLDOMDocumentPtr x;
    x.CreateInstance(__uuidof(DOMDocument));
    }
   CoUninitialize();
There is no possibility of a leak since the smart pointer IXMLDOMDocument does call Release() at the second brace. But as I said previously memory is allocated during the CreateInstance and not deallocated until much later.

In fact, I have stepped through sample code right into the CRT shutdown code. The exception is thrown in the very last statement executed in the process, the TerminateProcess() call.

Calling CoRevokeMallocSpy does not solve the problem. If there are outstanding allocations when a call is made to CoRevokeMallocSpy, it just returns E_ACCESSDENIED but does not stop COM from calling the IMallocSpy routines.

Part of the solution is to not deallocate the jComHeap object. That way the object still exists at DLL unload time. Ole32 calls PreFree and PostFree and finds a valid object still available and so no exception is thrown.

Note all of this does not mean that MSXML leaks memory. It does mean:

Which means that IMallocSpy and jComHeap will report memory leaks when there are none when you use MSXML.




Contact me about content on this page using john_web-at-arrizza-dot-com
For Web Master or site problems contact: webadmin-at-arrizza-dot-com
Copyright John Arrizza (c) 2001,2002,2003,2004,2005,2006,2007