I'm trying to locate a memory leak issue.
My project is an ATL based dialog project, that uses DirectShow and the standard library.
I get a total of 45 memory leaks in my program, all 24 bytes each.
I've #define'd _CRTDBG_MAP_ALLOC etc in my stdafx.h, along with DEBUG_NEW to get the file and line numbers for each of the memory leaks.
However, no file line numbers are printed. The memory blocks are all "normal" blocks and look like this:
{180} normal block at 0x003E6008, 24 bytes long. Data: < > _> > W > A0 AE 3E 00 B0 5F 3E 00 A0 AE 3E 00 57 00 00 00
I've tried adding the following line to the start of _tWinMain()
_CrtSetBreakAlloc(180);
in order to break on the allocation, but the debugger doesn't break at all.
Can anyone give me any insight into how I might track down the elusive memory leaks?
Finally, here's my _tWinMain() - I call _CrtDumpMemoryLeaks() just before exiting.
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow){
_CrtSetBreakAlloc(180);
HRESULT hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
ATLASSERT(SUCCEEDED(hRes));
::DefWindowProc(NULL, 0, 0, 0L);
AtlInitCommonControls(ICC_BAR_CLASSES);
//HINSTANCE开发者_StackOverflow社区 hInstRich = ::LoadLibrary(CRichEditCtrl::GetLibraryName());
hRes = _Module.Init(NULL, hInstance);
ATLASSERT(SUCCEEDED(hRes));
int nRet = Run(lpstrCmdLine, nCmdShow);
_Module.Term();
::CoUninitialize();
_CrtDumpMemoryLeaks();
return nRet;
}
Two suggestions.
Firstly, what gets constructed before main
(or equivalent) starts gets destroyed after main
finishes. Calling _CrtDumpMemoryLeaks
at the end of main
can give you false positives. (Or are they false negatives?) Global objects' destructors have yet to run, and atexit
callbacks have yet to run, so the leak output will include allocations that have simply yet to be correctly freed.
(I suspect this is why your global objects are appearing to leak. There may well be nothing wrong with the code, and indeed it's quite possibly cleaning itself up properly -- the cleanup code has simply yet to run when _CrtDumpMemoryLeaks
is being called.)
What you need to do instead is to direct the runtime library to call _CrtDumpMemoryLeaks
for you, right at the end, after all the atexit
callbacks and global object destructors have finished. Then you'll only see the genuine leaks. This snippet will do the trick. Stick at at the start of main
:
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)|_CRTDBG_LEAK_CHECK_DF);
Secondly, if the above reveals genuine leaks from stuff that runs before main
, you can do a bit of trickery to get some of your own code running pretty much before anything else gets a look in. Then you can set _crtBreakAlloc
before any allocations happen. Just pop the following code in a .cpp file of its own:
#include <crtdbg.h>
#ifdef _DEBUG
#pragma warning(disable:4074)//initializers put in compiler reserved initialization area
#pragma init_seg(compiler)//global objects in this file get constructed very early on
struct CrtBreakAllocSetter {
CrtBreakAllocSetter() {
_crtBreakAlloc=<allocation number of interest>;
}
};
CrtBreakAllocSetter g_crtBreakAllocSetter;
#endif//_DEBUG
(I suspect that code in the compiler's init segment may well run before stdin
and stdout
and the like are initialised, and certainly before any global objects are constructed, so you may have difficulty doing anything more complicated than the above!)
(For what little it's worth, I'm of the opinion these days, and have been for some time now, that allocation before main
starts is almost always a bad thing. Makes it hard to clean up after oneself, and difficult to keep track of what's going on. It's certainly convenient, but you always seem to end up paying for it later. That's advice that's much easier to hand out than it is to implement, though, particularly as part of a larger team.)
I had a couple of global variables (lookup tables that returned CString references to error messages) that I've removed from the program. As soon as I did - no memory leaks.
Thanks for your comments folks.
Interesting - I'll have to investigate a different way to implement error lookup.
I was doing something like:
CString sError = "error at line x: " + g_map.lookup(hrError);
The error map is implemented as an object that wraps access to an std::map, and it's destructor work fine. When I allocate this map object on the heap, and deallocate it, it reports no memory leaks. Maybe its the way I'm concatenating CString....
精彩评论