views:

94

answers:

2

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 hInstRich = ::LoadLibrary(CRichEditCtrl::GetLibraryName());

    hRes = _Module.Init(NULL, hInstance);
    ATLASSERT(SUCCEEDED(hRes));

    int nRet = Run(lpstrCmdLine, nCmdShow);

    _Module.Term();
    ::CoUninitialize();

    _CrtDumpMemoryLeaks();

    return nRet;
}
A: 

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....

freefallr
I understand the purity of wanting your code to be leak free. Just keep in mind that as long as (1) you don't have a long-running, on-demand application (e.g., a service that's available 24/7/365) and (2) the memory leaks are finite, it's not absolutely necessary that you fix them.
Matt Davis
Hi Matt - on the contrary - NEVER allow a memory leak no matter what the circumstances are. It's a best practice issue, and in the long run, when your app develops even more, you won't have to chase these leaks which might cause even bigger problems.
Poni
@Poni, I agree with the best practice sentiment. But I still stand by my original statement that under certain circumstances, a finite number of memory leaks are permissible.
Matt Davis
freefallr
+1  A: 

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.)

brone
Thanks for the input. I completely agree that allocation before main is a bad thing. I changed the program to allocate the global objects on the heap and this cut down many of the memory leaks. The few remaining were just carelessness on my part.I found your extra cpp file interesting - I'd not read an example of using CrtBreakAllocSetter before, and I'll certainly add it to my toolset...thanks
freefallr