C/C++ 内存泄漏检测工具 Visual Leak Detector

Table of Contents

这几天在用VLD(Visual Leak Detector)来检查内存泄露,感觉很好、很强大,所以推荐给大家。

下面的博文不会面面俱到,这也不是我的目的。我的目的是再看了这篇文章以后,不用看文档就可以实际的解决你的问题。当然,有时间、有精力的话推荐你去看这两篇文档:Visual Leak Detector - Enhanced Memory Leak Detection for Visual C++, Visual Leak Detector for Visual C++ 2008/2010/2012


1 VLD是什么

VLD 是专门是用来在 Visual C++ 2008/2010/2012 下开发的 C++ 项目检测内存泄露的一个工具,我觉得它更像一个库。从这里下载安装包(1M大小)。傻瓜式安装,不解释了。注意:VLD 只对 Debug 模式有效,对 Release 模式没什么影响。

2 VLD 的使用

  1. 将 VLD include 和 lib 路径加到你的工程中配置中(项目属性->VC++目录->包含文件/库目录)
  2. 将 vld.h include 到你的工程中的一个源文件中(任选一个即可),假如你的工程中使用了 DL L,请在 DLL 的源文件中也加入 vld.h (任选一个源文件),重新编译。
  3. 用 Debug 模式编译。

3 VLD的配置文件

配置文件在安装目录下(vld.ini),修改配置文件将会影响所有使用到 VLD 的工程。另外一种做法。将 vld.ini 复制到你的工程目录下(VS2010 C++工程放到 *.vcxproj 同级目录),然后修改,只会影响你的所在工程配置。

vld.ini 配置有几个选项,我只说一下我感觉很有用的:

  • VLD: 选择VLD的打开与关闭。在Debug模式下运行,关闭以后会有一行VLD关闭的提示信息。默认为 on。
  • gregateDuplicates: 这个非常有用,设置为 yes 时,相同地方产生内存泄漏只输出一次,但是会统计发生的次数。默认是 no 。
  • MaxDataDump: 输出的dump数据个数,默认为 256。
  • MaxTraceFrames: 官方文档解释的非常复杂,我的理解就是输出的调用栈的层数。默认是 64。
  • ReportEncoding report: 文件的编码格式,可选有 ascii, unicode,默认是 ascii 。
  • ReportFile: report 文件的路径。默认是 ".\memory_leak_report.txt"
  • ReportTo: 这个也是一个很有用的参数,可选有 debugger, file, both,debugger 表示输出到 debug模式下的输出窗口;file 表示只输出到文件中; both顾名思义,全都都输出。默认是 debugger 。具体用那个参数,看你的内存泄漏出现的多少了,自己衡量吧。

4 示例

#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;
}

可以看到我在 memleak 中开辟了两块内存,只释放了一次。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.
  1. Block 那一行说明了泄露大小;
  2. leakHash 那一行说明了同样地方出现泄露的次数(我的 vld.ini AggregateDuplicates = yes);
  3. Call Stack 调用堆栈这一块是最重要的,定位问题出现的模块(位置);
  4. Data 表示泄露的数据块中的数据,小工程比较有用。大工程数据看不来的。

所有的数据都输出到一个文件中,小工程还可以忍受,大工程成千上万个位置,肉眼根本无法辨识。所以我希望可以按照优先级来排序。由此,我自己用 C++ 写了一个小工具,实现了将 report 中的数据按照优先级进行排序(次数,单个内存泄露多少,该位置总共泄露多少)。排完序之后,我就可以优先处理内存泄漏比较严重的模块。没有写用户界面,连 dos 界面都没有,我感觉加一个界面需要的时候要快比我写核心代码耗时都要长,有些丑陋,不过很实用。源码挂到我的 github 上了,感兴趣可以去看看。

Date: 2013-03-21 13:32:43

Author: JerryZhang