我正在尝试查找内存泄漏问题。
我的项目是一个基于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
我尝试将以下行添加到_tWinMain()
的开头_CrtSetBreakAlloc(180);
为了打破分配,但调试器根本没有中断。
任何人都可以告诉我如何追踪难以捉摸的内存泄漏吗?
最后,这是我的_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;
}
答案 0 :(得分:7)
两个建议。
首先,在main
(或等效)开始之前构造的内容在main
完成后被销毁。在_CrtDumpMemoryLeaks
结束时拨打main
会给您带来误报。 (或者它们是否为假阴性?)全局对象的析构函数尚未运行,并且atexit
回调尚未运行,因此泄漏输出将包括尚未正确释放的分配。
(我怀疑这就是你的全局对象出现泄漏的原因。代码可能没有任何问题,实际上它很可能正确地清理自己 - 清理代码在{{1被调用。)
您需要做的是在所有_CrtDumpMemoryLeaks
回调和全局对象析构函数完成后,指示运行时库为您调用_CrtDumpMemoryLeaks
。然后你只能看到真正的泄漏。这个片段可以解决这个问题。坚持atexit
:
main
其次,如果上面的内容揭示了在_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)|_CRTDBG_LEAK_CHECK_DF);
之前运行的东西的真正泄漏,你可以做一些诡计,让你自己的代码运行得非常多,然后才能看到。然后你就可以了在任何分配发生之前设置main
。只需在自己的.cpp文件中弹出以下代码:
_crtBreakAlloc
(我怀疑编译器初始化段中的代码可能会在#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
和stdin
等之前运行,并且肯定会在构建任何全局对象之前运行,因此您可能无法做任何事情比上面更复杂!)
(虽然它的价值很小,但我现在已经有了这种观点,并且已经有一段时间了,stdout
开始之前的分配几乎总是一件坏事。以后很难清理。自己,很难跟踪发生了什么。这当然很方便,但你似乎总是在以后付钱。这个建议比实施要容易得多,特别是作为一个更大的一部分。队。)
答案 1 :(得分:0)
我从程序中删除了一些全局变量(返回CString对错误消息的引用的查找表)。我一做到了 - 没有内存泄漏。
感谢您的评论。
有趣 - 我将不得不研究一种不同的方法来实现错误查找。
我做的事情是:
CString sError = "error at line x: " + g_map.lookup(hrError);
错误映射实现为一个包装对std :: map的访问的对象,它的析构函数工作正常。当我在堆上分配这个映射对象并释放它时,它报告没有内存泄漏。也许是我连接CString的方式......