内存泄漏:无法中断内存分配号

5 c++ memory-leaks

我正在尝试找到内存泄漏问题.

我的项目是一个基于ATL的对话框项目,它使用DirectShow和标准库.

我的程序总共有45个内存泄漏,每个都有24个字节.

我在stdafx.h中定义了#defn _CRTDBG_MAP_ALLOC等,以及DEBUG_NEW来获取每个内存泄漏的文件和行号.

但是,不会打印文件行号.内存块都是"普通"块,如下所示:

{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 
Run Code Online (Sandbox Code Playgroud)

我已经尝试将以下行添加到_tWinMain()的开头

_CrtSetBreakAlloc(180);
Run Code Online (Sandbox Code Playgroud)

为了打破分配,但调试器根本没有中断.

任何人都可以告诉我如何追踪难以捉摸的内存泄漏?

最后,这是我的_tWinMain() - 我在退出之前调用_CrtDumpMemoryLeaks().

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;
}
Run Code Online (Sandbox Code Playgroud)

小智 7

两个建议.

首先,mainmain完成之前(或等效的)开始构造的内容在完成之后被破坏.呼吁_CrtDumpMemoryLeaks在年底main可以给你误报.(或者它们是否为假阴性?)全局对象的析构函数尚未运行,并且atexit回调尚未运行,因此泄漏输出将包括尚未正确释放的分配.

(我怀疑这就是你的全局对象出现泄漏的原因.代码可能没有任何问题,而且它很可能正确地清理自己 - 清理代码在_CrtDumpMemoryLeaks被调用时还没有运行.)

您需要做的是_CrtDumpMemoryLeaks在所有atexit回调和全局对象析构函数完成后,指示运行时库在最后调用.然后你只能看到真正的泄漏.这个片段可以解决这个问题.坚持在开始时main:

_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)|_CRTDBG_LEAK_CHECK_DF);
Run Code Online (Sandbox Code Playgroud)

其次,如果上面的内容揭示了以前运行的东西的真正泄漏main,你可以做一些技巧,让你自己的一些代码在其他任何东西看之前运行.然后你可以_crtBreakAlloc在任何分配发生之前设置.只需在自己的.cpp文件中弹出以下代码:

#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
Run Code Online (Sandbox Code Playgroud)

(我怀疑在编译器的初始化段代码可能之前运行stdin,并stdout与等初始化,并构建全球任何对象之前肯定,所以你可能很难做任何事情比上述更复杂!)

(虽然它的价值很小,但我现在已经有了这种观点,并且已经有一段时间了,在main开始之前的分配几乎总是一件坏事.让自己很难清理,很难跟踪发生了什么.这当然很方便,但是你似乎总是在以后付钱.这个建议比实施更容易分发,特别是作为一个更大的团队的一部分.)