Memory leaks when calling ITK from Visual Studio DLL
的后续问题我将问题提炼为最简单的例子。
struct A
{
public:
A()
{
mp_data = new int(0x42);
}
~A()
{
delete mp_data;
}
int* mp_data;
};
A a;
在DLL中定义此类全局类时,Visual Studio调试CRT会报告mp_data在应用程序关闭时泄露。除了禁用泄漏报告之外,有没有人知道解决方法?
答案 0 :(得分:5)
如果您在主要功能结束时调用_CrtDumpMemoryLeaks()
,则会出现行为,因为在mp_data
被调用后将删除_CrtDumpMemoryLeaks()
。
如果您不想看到这些泄漏(非常困难的任务),您需要在调用静态对象的最后一个析构函数之后调用_CrtDumpMemoryLeaks()
(或者在内存释放后的最后一个析构函数中调用) ,我不会尝试)。
更干净的方法是在堆上分配所有静态对象(在main
的开头),并在main
的末尾取消分配它们,然后你可以调用{{1并且不会看到任何内存泄漏。
带有构造函数和析构函数的FYI静态对象被认为是坏的,因为它们构造/解构的顺序不是确定性的,并且因为静态对象经常会引入无法轻松调试的错误。
关于安德烈评论的修改
您可以尝试通过调用_CrtSetDbgFlag取消设置_CrtDumpMemoryLeaks()
标志来停用对_CrtDumpMemoryLeaks
的自动调用。如果可行,您可以添加一个在其析构函数中调用_CRTDBG_LEAK_CHECK_DF
的静态对象。要确保最后销毁此对象,可以使用#pragma init_seg(compiler) directive。
不知道这是否有用......除此之外,所有其他解决方案很可能都需要您修改ITK库(这应该是可能的,毕竟它是一个开源库?!)。 / p>
答案 1 :(得分:2)
以下任何一个解决了这个问题。
(1)在MFC上创建DLL的伪依赖,或
(2)使用smerlin建议的解决方案:在DllMain
旁边添加此代码struct _DEBUG_STATE
{
_DEBUG_STATE() {}
~_DEBUG_STATE() { _CrtDumpMemoryLeaks(); }
};
#pragma init_seg(compiler)
_DEBUG_STATE ds;
答案 2 :(得分:2)
我在将内部库从静态链接迁移到加载时动态链接的过程中遇到了相同的症状,结果发现我的问题是DLL项目和EXE项目链接到不同的版本VC ++的运行时/ MFC库(一个是MBCS,一个是Unicode)。
在我的情况下,应用程序和库都使用MFC,并且激活CRT内存泄漏转储的_AFX_DEBUG_STATE析构函数被调用两次,用于两个单独的对象 - 因为DLL和EXE链接到不同的运行时DLL,静态运行时中的状态有效地重复。其中一个DLL会过早地卸载和转储泄漏并显示一堆虚假泄漏。将两个项目切换为使用相同的字符集解决了单独的运行时链接,并解决了错误泄漏报告。
就我而言,与两个独立运行时的链接是无意的,无论如何都可能引起其他问题。当使用定义明确的ABI的第三方库时,显然不会出现这种情况,因为您无法控制库链接到哪个CRT。
不确定这是否适用于您的情况,但我想发帖以防其他人有用。
答案 3 :(得分:0)
在MFC应用程序中,您可以通过调用以下方法禁用自动内存泄漏转储:
AfxEnableMemoryLeakDump(FALSE);
自Visual Studio 2010起支持此功能。有关文档,请参阅here。
答案 4 :(得分:0)
我在Visual Studio 2015中遇到了同样的问题。我尝试了所有解决方案。只有在Dll中选择编译器选项/MT
时,第一个带有假MFC依赖的解决方案才有效。所以你的Dll和主应用程序不会共享同一个堆。但通常需要/MD
,例如如果要在Dll和主应用程序(Dll边界)之间共享STL容器或字符串对象。如果使用/MD
,则app和Dll使用相同的堆。因此,假冒MFC依赖的第一个解决方案并不适用于我。
我不喜欢在主应用程序中禁用内存泄漏检测的第二种解决方案。如果您不再需要在析构函数中使用此调用的Dll,则必须记住在应用程序中重新激活内存泄漏检测。
我找到了另一个解决方案,所以我不再有虚假内存泄漏了。
您只需为您的Dll使用/delayload
链接器选项!全部:-)。它也适用于编译器选项/MD
。