还在苦苦敲代码开发APP?你out啦! 试试积木搭建APP吧~

VS Debug调试模式下内存泄露检测原理

来源:     2016-12-13 16:29:48    人气:     我有话说( 0 人参与)

内存泄露检测基本原理:程序调用new、malloc、realloc等内存分配函数时,将分配的内存地址,分配的大小、第几次分配、分配函数调用所在的文...

内存泄露检测基本原理:

程序调用new、malloc、realloc等内存分配函数时,将分配的内存地址,分配的大小、第几次分配、分配函数调用所在的文件名、所在的行数等这些信息记录到一个链表中。程序调用delete、free等内存释放函数时,通过释放的内存地址,查找链表,如果找到就将该内存地址对应的信息从链表中删除(如果未找到说明这个内存地址可能之前已经释放过了,或者根本就没分配过,可能存在潜在的问题)。程序退出的时候,如果链表还有数据,说明存在内存泄露,输出链表中的数据。

 

MS CRT已支持内存泄露的检测,使用MFC向导生成的工程,在DEBUG模式下,默认会开启内存泄露检测,程序退出时,如果有内存泄露,泄露的内存信息将在输出窗口中显示。

 

常见问题:

1. 为什么输出窗口有检测到内存泄露,但是没有显示文件名及第几行的信息?

   要检测内存泄露,首先要跟踪内存分配函数,所以要将new、malloc等内存函数接管过来。默认内存分配函数没有文件名和所在行的信息,于是CRT宏定义了malloc、realloc,如下:

#define   malloc(s)             _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
#define   calloc(c, s)          _calloc_dbg(c, s, _NORMAL_BLOCK, __FILE__, __LINE__)
#define   realloc(p, s)         _realloc_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__)

这样源代码中的所有malloc还有realloc,就都被替换为对应的有文件名和所在行的内存分配函数了。

这些宏定义生效需要定义_CRTDBG_MAP_ALLOC宏,可以在 项目-》C/C++-》预处理 中定义。

同理对于new,也要宏定义,将默认的new重定向到包含有文件名和行号的版本new(__FILE__, __LINE__)。

可以将如下一段代码保存到SetDebugNew.h文件中,

#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK   new(__FILE__, __LINE__)
#define new DEBUG_CLIENTBLOCK
#endif

在源代码文件中包含该头文件,如果有stdafx.h文件,在文件中#include "SetDebugNew.h",这样每个.c或.cpp文件就都使用debug的new版本。

 

2. 已经按照问题1的解决方案进行修订,但还是有内存泄露没有文件名和代码行号?

   没有文件名的内存泄露位置在于其他的模块,这些模块编译时没有按照问题1的解决方案进行修订。如果输出的内存泄露信息中,内存块号也就是内存在第几次中分配,如下所示的{354}就是内存块号。

Detected memory leaks!
Dumping objects ->
d:\local\project\test.cpp(278) : {354} normal block at 0x003FDAB8, 44 bytes long.
 Data: <    P-  P-      > 80 00 E4 00 50 2D E5 00 50 2D E5 00 CD CD CD CD
Object dump complete.

如果内存块号比较稳定,可以调用_CrtSetBreakAlloc,将块号作为参数设置一个断点。程序分配这个内存时将break,再查看调用堆栈。

 

3. 为什么程序退出时没有进行内存泄露检测?

   debug模式下,程序退出前会调用_CrtDumpMemoryLeaks函数进行内存泄露检测并输出。所以自己也可以调用_CrtDumpMemoryLeaks函数随时进行内存泄露检测输出,也可以使用如下代码设置内存检测输出标志让程序退出时自己调用。

#ifdef _DEBUG
 _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

 

4. 为什么在DLL中定义一个static对象,该对象在析构时会自动释放内存,但还是提示内存泄露?

   dll中static对象的析构函数时在dll的detach时才执行的,程序退出detach crt dll时会调用CrtDumpMemoryLeaks进行内存泄露检测并输出,如果dll的detach在crt dll detach之后,那么就会被误认为是内存泄露,此情况不用担心。

VS Debug 内存泄露 原理

本文源自互联网,采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可,
版权归原作者,如有问题请联系service@tsingfun.com (编辑:admin)
分享到: