我正在尝试找到内存泄漏问题.
我的项目是一个基于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
两个建议.
首先,main在main完成之前(或等效的)开始构造的内容在完成之后被破坏.呼吁_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开始之前的分配几乎总是一件坏事.让自己很难清理,很难跟踪发生了什么.这当然很方便,但是你似乎总是在以后付钱.这个建议比实施更容易分发,特别是作为一个更大的团队的一部分.)