.1. VS 2008 中内存泄露检查
检测内存泄漏的主要工具是调试器和 CRT 调试堆函数。若要启用调试堆函数,请在程序中包括以下语句:
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)
#endif
a) 通过包括 crtdbg.h,将 malloc 和 free 函数映射到其“Debug”版本_malloc_dbg 和_free_dbg,这些函数将跟踪内存分配和释放。此映射只在调试版本(在其中定义了 _DEBUG)中发生。发布版本使用普通的 malloc 和 free 函数
b) #define _CRTDBG_MAP_ALLOC语句将 CRT 堆函数的基版本映射到对应的“Debug”版本。并非绝对需要该语句,但如果没有该语句,内存泄漏转储包含的有用信息将较少。
c) 在添加了上面所示语句之后,可以通过在程序中包括以下语句来转储内存泄漏信息:
_CrtDumpMemoryLeaks();
当在调试器下运行程序时,_CrtDumpMemoryLeaks 将在“输出”窗口中显示内存泄漏信息。内存泄漏信息如下所示:
Dumpingobjects ->
X:XX.cpp(172): {1875} normal block at 0x00780E80, 78600 bytes long.//内存分配编号, 块类型(普通、客户端或CRT),内存位置,块大小
Data: <> CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD//前 16 字节内容(十六进制)
Object dumpcomplete.
----如果程序可以从多个位置退出,在程序开始包括以下调用:
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF |_CRTDBG_LEAK_CHECK_DF );
该语句在程序退出时自动调用 _CrtDumpMemoryLeaks。必须同时设置 _CRTDBG_ALLOC_MEM_DF 和 _CRTDBG_LEAK_CHECK_DF 两个位域,如上所示。
----确定内存泄露位置
添加如下一行(对于第 1875 个内存分配):
_crtBreakAlloc = 1875;//第1875次申请内存分配时
或者,可以使用具有同样效果的 _CrtSetBreakAlloc 函数:
_CrtSetBreakAlloc(1875);
在调试状态下运行序,在断点停下时,打开“调用堆栈”窗口,找到对应的源代码处;
退出程序,观察“输出窗口”的内存泄露报告,看实际内存分配的块号是不是和预设值相同,如果相同,就找到了;如果不同,就重复步骤3,直到相同。
(来源:http://blog.sina.com.cn/s/blog_4bf793ad0100jsxy.html)
2. 内存泄露的解决方法
Smartpointer ----STL中已经广泛应用
Garbadgecollection ----java
3. 内存泄露一般指堆内存泄露
Malloc、realloc、new三种方式申请堆内存
释放方式为: free、delete
4. 系统资源的泄漏(resource leak)
核心态HANDLE,GDIObject,SOCKET,Interface等,从根本上说这些由操作系统分配的对象也消耗内存,如果这些对象发生泄漏最终也会导致内存的泄漏
5. 如果要检测堆内存的泄漏,那么需要截获住 malloc/realloc/free和new/delete就可以了(其实new/delete最终也是用malloc/free的,所以只要截获前面一组即可)。对于其他的泄漏,可以采用类似的方法,截获住相应的分配和释放函数。比如,要检测BSTR的泄漏,就需要截获 SysAllocString/SysFreeString;要检测HMENU的泄漏,就需要截获CreateMenu/ DestroyMenu
6.windows平台内存泄露检测工具:
MSC-Runtime Library 内建检测功能;
第三方(外挂式)检测工具:Purify,boundschecker;
Windows自带的performancemonitor
7. BoundsChecker
采用一种被称为 Code Injection的技术,来截获对分配内存和释放内存的函数的调用。简单地说,当你的程序开始运行时,BoundsChecker的DLL被自动载入进程的地址空间(这可以通过system-level的Hook实现),然后它会修改进程中对内存分配和释放的函数调用,让这些调用首先转入它的代码,然后再执行原来的代码。BoundsChecker在做这些动作的时,无须修改被调试程序的源代码或工程配置文件,这使得使用它非常的简便、直接。
8.基类析构函数应声明为virtual
RAIIà构造函数中申请资源,析构函数中释放资源。例如:STL中的auto_ptr
9. 编码规范检查工具 CodeWizard
内置500多条编码规则,可随意组合
与vs c++无缝集成
10. 代码检查工具 PC-Lint
PC-Lint可检查编译器不易发现的错误。PC-Lint可对100多个C库函数进行检查,可以发现标准C/C++代码中的1 000多个常见错误。
11. 利用Purify和Insure++查找运行时内存缺陷
Rational Purify和Parasoft Insure++ 是用于运行时错误检查的工具。Purify主要检测:数组内存越界读/写,使用未初始化的内存,对已释放的内存进行读/写,内存泄漏等。Insure++ 利12.
用其专利技术(源码插装和运行时指针跟踪)能够发现大量的内存操作错误,报告错误的源代码行和执行轨迹。根据笔者的测试(基于98个有各种内存错误的 C++程序,涵盖了典型情形),Insure++ 6.1都能准确检测。
利用Windows结构化异常处理机制处理发布版本软件的内存崩溃
在程序的发布阶段,应尽量减少程序错误尤其是内存崩溃。如果崩溃了,应该“优雅”地退出,尽量收集程序崩溃时的运行信息以帮助程序供应商后续的调试。要捕捉内存非法访问并获知非法访问的指令地址、寄存器内容等信息,需要用到 Windows的结构化异常处理(Structured Exception Handling,SEH)机制[6]。MiniDumpWriteDump是dbghelp.dll提供的一个 API函数(参考MSDN),用于转储用户模式程序的一些信息(比如堆栈情况等)并存为一个文件(比如.dmp文件),此文件可以被微软的调试器
(VC++或者WinDBG)利用进行事后调试。使用此函数需要dbghelp.h、dbghelp.lib和dbghelp.dll(这些文件可以在 Windows Platform SDK中找到)。
要事后根据.dmp文件调试代码,需要为发布版本软件产生debug symbols (pdb)文件(打开编译器/DEBUG选项)。在拿到.dmp文件以后,用VC++打开.dmp文件,然后调试执行(按F5键)。这样,崩溃现场就会重现。文献[5]基于上述的方法实现了崩溃报告系统