Use jComHeap to discover COM heap leaks. For an example of how to use it see testjComHeap.cpp.
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.
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().
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:
| 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 |