API that allows user code to monitor COM memory allocations and deallocations
This includes memory allocations made explicitly by user code
as well as memory allocations made implicitly by COM runtime
on behalf of the user.
Experiment shows that on Windows 2000/XP some memory still remains
allocated even after COM has been shut down by calling
. This memory is eventually
freed by program termination code in
Behavior on Windows XP is the same.
This makes detection of COM memory leaks difficult. At no moment in our program we can say "OK, all COM memory should be released by now. If anything is not released, it is definitely a leak".
Life used to be easier on Windows NT. On Windows NT
released all the memory
allocated by COM runtime. Thus, a good time to check
for leaks was right after
Anything not released by then could be safely declared a leak.
Windows 2000 introduces a new system DLL named
This DLL is loaded by COM runtime when you call
(and of course porbably in some other cases too).
startup code located in
allocates some COM memory using
. This memory is released by
shutdown code, also in
The caveat is that
clbcatq.dll! This appears to contradict
clbcatq.dll DLL gets unloaded
upon program termination. The memory is released
at this time using
MallocSpyTestis a console application. It tries to create an instance of a COM coclass specified on the command line. It also implements
IMallocSpyinterface and prints to standard output information about all COM alocations and deallocations.
it tries to revoke
malloc spy, and displays list of memory blocks that are not freed.
Test project can be invoked as follows:
You can use any COM coclass you like instead of
C:\TEMP>MallocSpyTest.exe ADODB.Recordset CoInitialize() returns 0x00000000 CoRegisterMallocSpy() returns 0x00000000 CLSIDFromProgID() returns 0x00000000 MALLOC SPY: 0x00139E90 - 216 bytes allocated MALLOC SPY: 0x00138650 - 16 bytes allocated MALLOC SPY: 0x00139F70 - 16 bytes allocated CoCreateInstance() returns 0x00000000 Object released MALLOC SPY: 0x00138650 - freed, 2 blocks remaining MALLOC SPY: 0x00139F70 - freed, 1 blocks remaining MALLOC SPY: 0x00139E90 - freed, 0 blocks remaining Called CoUninitialize() CoRevokeMallocSpy() returns 0x00000000 C:\TEMP>
However, results on Windows 2000 are astonishing:
C:\Ivan\cpp\MallocSpyTest>MallocSpyTest ADODB.Recordset CoInitialize() returns 0x00000000 CoRegisterMallocSpy() returns 0x00000000 MALLOC SPY: 0x0013BBB0 - 28 bytes allocated more allocations... CLSIDFromProgID() returns 0x00000000 [...] CoCreateInstance() returns 0x00000000 Object released [...] MALLOC SPY: 0x0013C150 - freed, 18 blocks remaining [...] Called CoUninitialize() CoRevokeMallocSpy() returns 0x80070005 MALLOC SPY: detected memory leaks! 0x0013A8F8 - 44 bytes: 98 B1 5A 77 08 BC 13 00 01 00 00 00 01 00 11 00 ..Zw............ more leaks... MALLOC SPY: 0x0013C0C0 - freed, 11 blocks remaining [...] MALLOC SPY: 0x0013BED0 - freed, 1 blocks remaining
Take a note of two things:
fails with error code is
0x8007005which stands for
E_ACCESSDENIED. I.e., we are not allowed to revoke the spy, despite the fact that COM has been shut down. This obviously makes using spy very problematic.
Since our spy continues to work while the program is being
terminated, and continues to call
, weird things happen.
is not really
designed to work during
One side effect of this is that if you redirect output of
MallocSpyTest to a file (as in
MallocSpyTest ADODB.Recordset >out.txt ),
last lines of output won't go to the file.
Results on XP are similar to those on 2000, main difference is more allocations.