这几天在用VLD(Visual Leak Detector)来检查内存泄露,感觉很好、很强大,所以推荐给大家。
下面的博文不会面面俱到,这也不是我的目的。我的目的是再看了这篇文章以后,不用看文档就可以实际的解决你的问题。当然,有时间、有精力的话推荐你去看这两篇文档:Visual Leak Detector – Enhanced Memory Leak Detection for Visual C++, Visual Leak Detector for Visual C++ 2008/2010/2012。
VLD是什么
VLD 是专门是用来在 Visual C++ 2008/2010/2012 下开发的 C++ 项目检测内存泄露的一个工具,我觉得它更像一个库。从这里下载安装包(1M大小)。傻瓜式安装,不解释了。注意:VLD 只对 Debug 模式有效,对 Release 模式没什么影响。
VLD 的使用
- 将 VLD include 和 lib 路径加到你的工程中配置中(项目属性->VC++目录->包含文件/库目录)
- 将 vld.h include 到你的工程中的一个源文件中(任选一个即可),假如你的工程中使用了 DL L,请在 DLL 的源文件中也加入 vld.h (任选一个源文件),重新编译。
- 用 Debug 模式编译。
VLD的配置文件
配置文件在安装目录下(vld.ini),修改配置文件将会影响所有使用到 VLD 的工程。另外一种做法。将 vld.ini 复制到你的工程目录下(VS2010 C++工程放到 *.vcxproj 同级目录),然后修改,只会影响你的所在工程配置。
vld.ini 配置有几个选项,我只说一下我感觉很有用的:
-
VLD
- 选择VLD的打开与关闭。在Debug模式下运行,关闭以后会有一行VLD关闭的提示信息。默认为 on。 AggregateDuplicates
- 输出的dump数据个数,默认为 256。 MaxTraceFrames
- 官方文档解释的非常复杂,我的理解就是输出的调用栈的层数。默认是 64。 ReportEncoding report
- 文件的编码格式,可选有 ascii, unicode,默认是 ascii 。 ReportFile
- report 文件的路径。默认是 “.\memory_leak_report.txt” ReportTo
- 这个也是一个很有用的参数,可选有 debugger, file, both,debugger 表示输出到 debug模式下的输出窗口;file 表示只输出到文件中; both顾名思义,全都都输出。默认是 debugger 。具体用那个参数,看你的内存泄漏出现的多少了,自己衡量吧。
这个非常有用,设置为 yes 时,相同地方产生内存泄漏只输出一次,但是会统计发生的次数。默认是 no 。
MaxDataDump示例
#include <iostream>
#include <vld.h>
void
mem_leak()
{
int
* p =
new
int
[100];
int
* p1 =
new
int
[1000];
delete
[] p;
}
int
main()
{
mem_leak();
return
0;
}
|
可以看到我在 mem_leak 中开辟了两块内存,只释放了一次。VLD 的报告如下:
Visual Leak Detector Version 2.2.3 installed.
Aggregating duplicate leaks.
Outputting the report to the debugger and to D:\Temp\testcpp1\testcpp1\memory_leak_report.txt
WARNING: Visual Leak Detector detected memory leaks!
---------- Block 2 at 0x005134F0: 4000 bytes ----------
Leak Hash: 0xB0F8FE58 Count: 1
Call Stack:
d:\temp\testcpp1\testcpp1\main.cpp (8): testcpp1.exe!mem_leak + 0xA bytes
d:\temp\testcpp1\testcpp1\main.cpp (15): testcpp1.exe!main
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (555): testcpp1.exe!__tmainCRTStartup + 0x19 bytes
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (371): testcpp1.exe!mainCRTStartup
0x758E3677 (File and line number not available): kernel32.dll!BaseThreadInitThunk + 0x12 bytes
0x77829F42 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x63 bytes
0x77829F15 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x36 bytes
Data:
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
Visual Leak Detector detected 1 memory leak (4036 bytes).
Largest number used: 4472 bytes.
Total allocations: 4472 bytes.
Visual Leak Detector is now exiting.
|
Block 那一行说明了泄露大小;
leakHash 那一行说明了同样地方出现泄露的次数(我的 vld.ini AggregateDuplicates = yes);
Call Stack 调用堆栈这一块是最重要的,定位问题出现的模块(位置);
Data 表示泄露的数据块中的数据,小工程比较有用。大工程数据看不来的。
所有的数据都输出到一个文件中,小工程还可以忍受,大工程成千上万个位置,肉眼根本无法辨识。所以我希望可以按照优先级来排序。由此,我自己用 C++ 写了一个小工具,实现了将 report 中的数据按照优先级进行排序(次数,单个内存泄露多少,该位置总共泄露多少)。排完序之后,我就可以优先处理内存泄漏比较严重的模块。没有写用户界面,连 dos 界面都没有,我感觉加一个界面需要的时候要快比我写核心代码耗时都要长,有些丑陋,不过很实用。源码挂到我的 github 上了,感兴趣可以去看看。