在进行C++开发时,如果在windows平台上,使用MFC,则可以自动检测内存泄露,如果是win32或者console程序,不使用MFC,则需要自己进行处理。
下面是在总结的一些方法,均来自网上,也经历了实际检验,在此备份。
1. 利用 KDetectMemoryLeak.h来完成类似MFC重定义NEW宏的效果。可以完成泄露点的输出。
在代码的最后,采用_CrtDumpMemoryLeaks();
具体可以参见《VS2008内存泄露检测》文档,作者写的很清楚,在此谢谢。
KDetectMemoryLeak.h 源码:
#pragma once
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__,__LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
2. 对于无法定位到具体源代码的泄露,可以通过分析dump出来的信息来定位。
特别是在DLL库中,经常会出现这种情况。
比如:
{152} normal block at 0x01078320, 12 bytes long.
Data: 08 79 65 00 48 82 07 01 00 00 00 00
{151} normal block at 0x010782C0, 36 bytes long.
Data: CD CD CD CD CD CD CD CD 00 00 00 00 00 00 0000
{150} normal block at 0x01078248, 56 bytes long.
Data: F4 77 65 00 00 00 00 00 68 71 07 01 90 3A 0910
《软件调试》的702页介绍了堆块转储的细节,取其中的一个堆块为例:
{137} normal block at 0x01073790, 8 bytes long.
Data: <H7> 48 37 07 01 CD CD CD CD
137是堆块的分配序号,堆块的类型为普通堆块,位置为0x01073790,用户区长度为8字节。
Data后为用户数据区的前16字节,因为这个数据区只有8字节,所以即所有8字节。<H7>是这8字节的ASCII码显示(其它6字节为不可显示的ASCII码)。其中的CD CD CDCD 是CRT在分配堆块时自动填充的固定内容(《软件调试》P696)。这说明这8个字节的堆块,应用程序使用过前4个字节,后四个字节没有使用过。
对于这样的内存泄漏,有很多种办法,你首先可以试一下23.13.1节介绍的内存分配序号断点,也就是重新运行程序,在尽可能早的时候(比如入口),设置序号断点(将_crtBreakAlloc变量设置为要中断的序号,比如137),让CRT分配到指定的内存块时中断。中断下来后,可以根据栈回溯判断是哪个模块在分配内存,记录后,再退出程序,如果这个堆块仍出现在转储列表中,那么刚才那个模块便值得怀疑了。
如果你有被怀疑的模块源代码,那么可以使用23.15.3节介绍的方法让堆块转储信息中包含源程序的文件名和行号,即下面的样子:
C:\dig\dbg\author\code\chap23\MemLeak\MemLeak.cpp(22): {74} normal block at 0x00371000, 20 bytes long.
Data: CD CD CD CD CD CD CD CD CD CD CD CD CD CD CDCD
3.可以利用 vld 进行检测。
4.还可以利用 boundcheck,purify等工具进行检测。