【问题标题】:Locating Memory Leaks定位内存泄漏
【发布时间】:2014-08-13 14:30:49
【问题描述】:

我目前正在调试一些代码,使用带有 CrtDbg 的 Visual Studio 2012 删除或至少定位内存泄漏。

问题是,只要分配号不变,追踪分配是相当容易的。当分配数变化很大(或不是真正确定的)时,我如何定位该泄漏的分配点?我至少可以说,哪个模块分配了内存?

我在关闭应用程序时有以下几行:

Detected memory leaks!
Dumping objects ->
{2789444} normal block at 0x0000000006103CB0, 32 bytes long.
 Data: < q f            > B8 71 E4 66 00 00 00 00 00 00 00 00 00 00 00 00 
{1269709} normal block at 0x000000000A50C6A0, 1008 bytes long.
 Data: <        )       > 01 00 00 00 0B 00 00 00 29 00 00 00 CD CD CD CD 
...
{2194} normal block at 0x0000000000278060, 16 bytes long.
 Data: <                > 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
Object dump complete.

最后一个分配号 2194 是可重现的,并且与静态初始化器有关。但其他数字正在发生变化。

我不能使用地址来定位它吗?还是有更简单的解决方案?

帮助会很大。

【问题讨论】:

  • 是否可以在这段代码中使用像 valgrind 这样的分析器?
  • 不,它是一个原生的 Windows 应用程序。
  • 啊,好吧,有这个想法:(
  • 已经想到了……Valgrind 看起来很酷……在 Linux 上时
  • 如果它不是本机应用程序,它可能是一种选择;)

标签: c++ visual-studio-2012 memory-leaks


【解决方案1】:

我建议您使用视觉检漏仪。我应该为您提供您需要的所有详细信息,以便您可以跟踪泄漏并且易于安装。 见here

【讨论】:

  • 已经试过了。但问题是生成这些分配的代码可能是没有源代码的第三方。或者我可以在不包含在正确文件中的情况下使用它吗?我不这么认为。
  • 如果是没有调试信息的第三方库,不管你做什么都是不走运的。你能得到的最好的,实际上是查明泄漏到一个特定的库。
  • 这就是我想做的。但是我如何(容易?)将泄漏与特定库匹配。有什么建议吗?
  • 分析器(我不熟悉 VLD - 免责声明)应该告诉您泄漏源自哪个模块/库/目标文件,至少。如果您有调试信息,那么您可以查看它是否是您可能正在使用(或使用不正确)的功能。
【解决方案2】:

试试Debug Diagnostic Tool v2.0,它是Windows上一个非常好的内存检测工具,它来自微软并且是免费的。

如果 3rd 方库泄漏内存,该工具可以定位该库,而无需调用堆栈信息。

要通过此调试器启动 exe,请转到菜单“工具”->“预附加配置”,为您的 exe 启用预附加调试器。

【讨论】:

  • 嗯,我试试。听起来很有希望。
  • 但只能附加到正在运行的进程。我会看看结果是什么...... :)
  • 它并没有真正起作用。如何直接从 DebugDiag 启动我的应用程序?
  • 没有真正的工作。得到太多误报。非常适合 .NET 应用程序,但不适用于本机代码 :(
【解决方案3】:

你可以使用这些技巧:

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
class MemChecker 
{
   friend class foo;
   struct foo 
   {
      HANDLE hLogFile;
      _CrtMemState _ms; 

      foo() 
      {
         hLogFile = CreateFile(TEXT("memory_leaks.txt"), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

         _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); // enable file output
         _CrtSetReportFile( _CRT_WARN, hLogFile ); // set file to stdout
         _CrtMemCheckpoint(&_ms); // now forget about objects created before

         // breaks on N-th memory allocation
         // look for this number in report file (in curved brackets)
         //_CrtSetBreakAlloc(1518);
      }
      ~foo() 
      { 
         _CrtMemDumpAllObjectsSince(&_ms); // dump leaks
         CloseHandle(hLogFile);
      }
   };
   static foo obj;
};
MemChecker::foo MemChecker::obj;

使用此声明,每次运行程序时,都会以适当的方式检测并报告内存泄漏。

此外,您可以将断点设置为特定的内存泄漏(读取代码中的 cmets)。怎么做:你运行应用程序,看看有多少内存泄漏,然后设置_CrtSetBreakAlloc(2789444*),所以下次你运行应用程序时——它会在分配内存(泄漏)的地方中断.

您可以更仔细地阅读有关标志 _CRTDBG_MODE_FILE、_CRTDBG_MODE_DEBUG 的信息,以指定将输出调试消息的位置。

*从您的示例中,{2789444} 正常块位于 0x0000000006103CB0,32 字节长。

【讨论】:

【解决方案4】:

下载visual-leak-detector 并开始以下操作:

创建以下目录结构:

Visual Leak Detector
    include
        vld.h
        vld_def.h
    lib
        Win32
            vld.lib
        Win64
            vld.lib
    bin
        Win32
            vld_x86.dll
        Win64
            vld_x64.dll

在你的主函数上方添加以下内容:

#ifdef _DEBUG_MEM
#include <vld.h>
#endif

在您的项目设置中添加以下内容:

_DEBUG_MEM in the preprocessor-definitions
Visual Leak Detector\include in the include-path
Visual Leak Detector\lib\Win<xx> in the library-path
Visual Leak Detector\bin\Win<xx> in the executable-path

【讨论】:

  • 我发现它会产生误报
  • 根据我的经验,没有任何分析器是完美的。它通常是一种复杂代码中受过教育的猜谜游戏。
  • 我为什么需要另一个 LeakDetector? WinDbg 已经包含在内,并且拥有使用这些功能的跟踪例程。问题不是我的代码,泄漏来自第三方库,没有附带调试信息或泄漏跟踪。
猜你喜欢
  • 1970-01-01
  • 2011-10-22
  • 1970-01-01
  • 1970-01-01
  • 2015-02-12
  • 2013-09-13
  • 2013-06-05
  • 2011-09-19
相关资源
最近更新 更多