6

从 Visual Studio DLL 调用 ITK 时内存泄漏的后续问题

我将问题细化为最简单的例子。

struct A
  {
  public:
    A()
      {
      mp_data = new int(0x42);
      }
    ~A()
      {
      delete mp_data;
      }
    int* mp_data;
  };

A a;

在 DLL 中定义此类全局类时,Visual Studio 调试 CRT 报告 mp_data 在应用程序关闭时泄漏。除了禁用泄漏报告之外,有人知道解决方法吗?

4

5 回答 5

5

如果您_CrtDumpMemoryLeaks()在 main 函数的末尾调用,则该行为是预期的,因为在调用mp_data后将被删除_CrtDumpMemoryLeaks()

如果您_CrtDumpMemoryLeaks()不想看到这些泄漏(这是一项艰巨的任务,我不会尝试一下)。

更简洁的方法是在堆上分配所有静态对象(在开头main),并在结尾处取消分配它们main,然后您可以调用_CrtDumpMemoryLeaks()并且不会看到任何内存泄漏。

仅供参考,带有构造函数和析构函数的静态对象无论如何都被认为是不好的,因为它们的构造/销毁顺序不是确定性的,因此静态对象通常会引入无法轻松调试的错误。

编辑关于 Andrey 的评论: 您可以尝试_CrtDumpMemoryLeaks通过调用_CrtSetDbgFlag取消设置_CRTDBG_LEAK_CHECK_DF标志来停用自动调用。如果可行,您可以添加一个调用_CrtDumpMemoryLeaks()其析构函数的静态对象。为了确保这个对象最后被破坏,你可以使用#pragma init_seg(compiler) 指令

不知道这是否可行……除此之外,所有其他解决方案很可能需要您修改ITK 库(这应该是可能的,毕竟它是一个开源库?!)。

于 2012-04-24T15:27:43.470 回答
2

以下任何一项都可以解决问题。

(1) 在 MFC 上创建 DLL 的虚假依赖项,或者

(2) 使用 smerlin 建议的解决方案:在 DllMain 旁边添加此代码

struct _DEBUG_STATE
  {
  _DEBUG_STATE() {}
  ~_DEBUG_STATE() { _CrtDumpMemoryLeaks(); }
  };

#pragma init_seg(compiler)
_DEBUG_STATE ds;
于 2012-04-25T09:40:28.790 回答
2

我在将内部库从静态链接迁移到加载时动态链接的过程中遇到了同样的症状,结果发现我的问题是 DLL 项目和 EXE 项目链接到了不同版本的 VC++ 运行时/MFC 库(一个是 MBCS,一个是 Unicode)。

在我的情况下,应用程序和库都使用 MFC,并且激活 CRT 内存泄漏转储的 _AFX_DEBUG_STATE 析构函数被调用了两次,用于两个单独的对象——因为 DLL 和 EXE 链接到不同的运行时 DLL,静态状态在运行时被有效地复制。其中一个 DLL 会过早卸载和转储泄漏,并显示一堆虚假泄漏。将两个项目切换为使用相同的字符集解决了单独的运行时链接并解决了错误的泄漏报告。

就我而言,链接到两个单独的运行时是无意的,并且可能无论如何都会导致其他问题。当使用具有明确定义的 ABI 的第三方库时,显然不会出现这种情况,您无法控制库链接到的 CRT。

不确定这是否适用于您的情况,但我想发布以防它对其他人有帮助。

于 2014-02-05T18:23:46.887 回答
0

在 MFC 应用程序中,您可以通过调用禁用自动内存泄漏转储:

AfxEnableMemoryLeakDump(FALSE);

自 Visual Studio 2010 起支持此功能。有关文档,请参见此处

于 2015-08-24T15:31:37.043 回答
0

我在 Visual Studio 2015 中遇到了同样的问题。我尝试了所有解决方案。仅当您/MT在 Dll 中选择编译器选项时,第一个具有假 MFC 依赖项的解决方案才有效。所以你的 Dll 和主应用程序不会共享同一个堆。但通常/MD是需要的,例如,如果您想在 Dll 和您的主应用程序(Dll 边界)之间共享 STL 容器或字符串对象。如果/MD使用,app 和 Dll 使用相同的堆。所以第一个具有假 MFC 依赖的解决方案对我不起作用。

我不喜欢第二种解决方案,即在主应用程序中禁用内存泄漏检测。当您不再需要在析构函数中调用此 Dll 时,您必须记住在应用程序中重新激活内存泄漏检测。

我找到了另一个解决方案,所以我不再有错误的内存泄漏。您只需/delayload为您的 Dll 使用链接器选项!就这样 :-)。它也适用于编译器选项/MD

在这里您可以阅读有关 Dll-boundary 的内容(为什么要使用/MD?)。在这里,您可以阅读有关 CRT 编译器选项的一般信息。

于 2016-12-23T13:31:38.060 回答