Muponder

为者常成,行者常至。

C++博客 首页 新随笔 联系 聚合 管理
  1 Posts :: 7 Stories :: 7 Comments :: 0 Trackbacks

    检测内存泄漏的主要工具是调试器和C运行库(CRT)调试堆函数,如果启动调试堆函数,请在程序中包括以下语句:

       1 #define _CRTDBG_MAP_ALLOC
      2 #include <stdlib.h>
      3 #include <crtdbg.h>
       注意:为了使CRT函数能够正常工作,#include语句必须遵循上面语句声明的次序。
       使用这些语句启用调试堆函数之后,可以在某个应用程序退出点之前设置一个对 _CrtDumpMemoryLeaks()的调用,以便在应用程序退出时显示内存泄漏报告:
         如果应用程序有多个退出点,并不需要在每个退出点都手动设置一个对 _CrtDumpMemoryLeaks() 的调用。 应用程序开头部分对 _CrtSetDbgFlag 的调用会导致在每个退出点自动调用 _CrtDumpMemoryLeaks 您必须设置两个位域,如下所示:
        
         
1 _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
         默认情况下,_CrtDumpMemoryLeaks 将内存泄漏报告输出到“输出”窗口的“调试”窗格中。 您可以使用_CrtSetReportMode 将该报告重定向到其他位置。
        
如果使用库,该库可能会将输出重置到另一位置。 在此情况下,可以将输出位置设置回“输出”窗口,如下所示:
       
1  _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );
       

          如果应用程序未定义 _CRTDBG_MAP_ALLOC,则 _CrtDumpMemoryLeaks 显示的内存泄漏报告如下所示:

Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00780E80, 64 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

            如果应用程序定义了 _CRTDBG_MAP_ALLOC,则显示的内存泄漏报告如下所示:

Detected memory leaks!
Dumping objects ->
C:\PROGRAM FILES\VISUAL STUDIO\MyProjects\leaktest\leaktest.cpp(20) : {18} 
normal block at 0x00780E80, 64 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

      区别在于,第二份报告显示文件名,以及泄漏的内存初次分配所在位置的行号。

      不论是否定义 _CRTDBG_MAP_ALLOC,内存泄漏报告都显示以下信息:

  • 内存分配编号,在本例中为 18

  • 块类型,在本例中为 normal

  • 十六进制内存位置,在本例中为 0x00780E80

  • 块的大小,在本例中为 64 bytes

  • 块中前 16 个字节的数据(十六进制形式)。

内存泄漏报告将内存块标识为普通、客户端或 CRT。 “普通块”是由程序分配的普通内存。 “客户端块”是由 MFC 程序用于需要析构函数的对象的特殊类型内存块。 MFC new 运算符根据正在创建的对象的需要创建普通块或客户端块。 “CRT 块”是由 CRT 库为自己使用而分配的内存块。 CRT 库可处理这些块的释放。 因此,您不大可能在内存泄漏报告中看到这些块,除非出现严重错误(例如 CRT 库损坏)。

内存泄漏报告中绝对不会出现另外两个内存块类型。 “可用块”是已释放的内存。 也就是说,根据定义,这种块不会泄漏。 “忽略块”是已明确标记、不出现在内存泄漏报告中的块。

如果分配了泄漏内存块,内存分配编号会通知您。 例如,内存分配编号为 18 的块就是在应用程序运行过程中所分配的第 18 个内存块。 CRT 报告包含运行过程中的所有内存块分配情况。 其中包括 CRT 库和其他库(如 MFC)的分配情况。 因此,内存分配编号为 18 的块可能不是您的代码所分配的第 18 个内存块。 通常,二者并不一致。

可以使用分配编号在内存分配位置设置断点。

使用“监视”窗口设置内存分配断点

  1. 在应用程序的起点附近设置断点,然后启动应用程序。

  2. 当应用程序在断点处中断时,会出现“监视”窗口。

  3. “监视”窗口中,在“名称”列中键入 _crtBreakAlloc

    如果要使用 CRT 库的多线程 DLL 版本(/MD 选项),请加入上下文运算符:{,,msvcr100d.dll}_crtBreakAlloc

  4. “Return”

    调试器将计算调用,并将结果放入“值”列。 如果没有在内存分配上设置任何断点,该值将为 –1。

  5. “值”列中,将显示的值替换为要在其位置中断的内存分配的分配编号。

在某个内存分配编号设置断点之后,您可以继续调试。 请注意在与以前运行相同的条件下运行程序,以便内存分配顺序不会更改。 当程序在指定的内存分配处中断时,可以使用“调用堆栈”窗口和其他调试器窗口来确定分配内存时的情况。 然后,可以继续执行程序以观察对象发生什么情况,并确定未正确释放对象的原因。

也可以在代码中设置内存分配断点。 有两种方法可以实现此目的:

_crtBreakAlloc = 18; 

或:

_CrtSetBreakAlloc(18);
posted on 2013-11-24 16:30 盛源博 阅读(237) 评论(0)  编辑 收藏 引用 所属分类: visual stdio

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理