使用_CrtSetDbgFlag检测内存泄露

来源:互联网 发布:分类算法应用场景 编辑:程序博客网 时间:2024/04/29 14:17

介绍:

动态分配、回收内存是C/C++编程语言一个最强的特点,但是中国哲学家孙(Sun Tzu,我不知道是谁?那位知道?)指出,最强的同时也是最弱的。这句话对C/C++应用来说非常正确,在内存处理出错的地方通常就是BUGS产生的地方。一个最敏感和难检测的BUG就是内存泄漏-没有把前边分配的内存成功释放,一个小的内存泄漏可能不需要太注意,但是程序泄漏大块内存,或者渐增式的泄漏内存可能引起的现象是:先是性能低下,再就是引起复杂的内存耗尽错误。最坏的是,一个内存泄漏程序可能用完了如此多的内存以至于引起其他的程序出错,留给用户的是不能知道错误到底来自哪里。另外,一个看上去无害的内存泄漏可能是另一个问题的先兆。幸运的是VC++DEBUGER和CRT库提供了一组有效的检测和定位内存泄漏的工具。本文描述如何使用这些工具有效和系统的排除内存泄漏。

_CrtDumpMemoryLeaks()就是检测从程序开始到执行该函数进程的堆使用情况,通过使用_CrtDumpMemoryLeaks()我们可以进行简单的内存泄露检测。

启用内存泄露检测:

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

#define _CRTDBG_MAP_ALLOC

#include <stdlib.h>

#include <crtdbg.h>

注意:

#include必须按照以上所示顺序。如果更改了顺序,所使用的函数可能无法使用。

通过包括crtdbg.h,将 malloc 和 free 函数映射到其“Debug”版本 _malloc_dbg 和 _free_dbg,这些函数将跟踪内存分配和释放。此映射只在调试版本(在其中定义了_DEBUG)中发生。发布版本使用普通的 mallocfree 函数。

#define语句将 CRT 堆函数的基版本映射到对应的“Debug”版本。并非绝对需要该语句,但如果没有该语句,内存泄漏转储包含的有用信息将较少。

在添加了上面所示语句之后,可以通过在程序中包括以下语句来转储内存泄漏信息:

_CrtDumpMemoryLeaks()

使用示范:

#define _CRTDBG_MAP_ALLOC

#include<stdlib.h>

#include<crtdbg.h>

#definenewnew( _CLIENT_BLOCK, __FILE__, __LINE__)

intmain()

{

int* leak = newint[10];

_CrtDumpMemoryLeaks();

}

这个示范程序与前面讲的多了一个宏定义:

#definenewnew( _CLIENT_BLOCK, __FILE__, __LINE__)

原因稍后再说,我们先看看程序运行(提醒:不要按Ctrl+F5,按F5)后的结果。

程序调试后在“输出”窗口输出如下:

Detected memory leaks!

Dumping objects ->

e:\work\myproject\test\test\test.cpp(57) : {48} client block at 0x00392BB0, subtype 0, 40 bytes long.

Data: <> CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD

Object dump complete.

“输出”很明显的告诉了你在test.cpp文件的第57行分配了一个40字节的内存而没有释放。在“输出”窗口中选择包含文件名和行号的行,然后按 F4 键即可进入到源文件中分配内存的行。

现在我们再来看看如果不加之前那个new的宏定义会出现怎么样的结果。

程序调试后在“输出”窗口输出如下:

Detected memory leaks!

Dumping objects ->

{48} normal block at 0x00392BB0, 40 bytes long.

Data: <> CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD

Object dump complete.

与之前的对比,这次的输出并没有告诉我们这个内存泄露具体是在哪个位置引起的。另外如果没定义

#define_CRTDBG_MAP_ALLOC

也会引起同样的结果。


_CrtSetDbgFlag

如果程序总是在同一位置退出,调用 _CrtDumpMemoryLeaks 将非常容易。如果程序从多个位置退出,则无需在每个可能退出的位置放置对 _CrtDumpMemoryLeaks 的调用,而可以在程序开始处包含以下调用:

_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

该语句在程序退出时自动调用 _CrtDumpMemoryLeaks。必须同时设置 _CRTDBG_ALLOC_MEM_DF_CRTDBG_ALLOC_MEM_DF 两个位域,如上所示。

设置 CRT 报告模式

默认情况下,_CrtDumpMemoryLeaks 将内存泄漏信息转储到“输出”窗口的“调试”窗格,如上所述。可以使用 _CrtSetReportMode 重置该设置,以转储到另一位置。如果使用库,它可以将输出重置到另一位置。在此情况下,可以使用以下语句将输出位置设置回“输出”窗口:

_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );