﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-iniwf-随笔分类-调试技术</title><link>http://www.cppblog.com/iniwf/category/9936.html</link><description>风是温柔的，雨是伤心的，云是快乐的，月是多情的，爱是迷失的，恋是醉人的，情是难忘的，天是长久的，地是永恒的</description><language>zh-cn</language><lastBuildDate>Mon, 31 Aug 2009 01:44:37 GMT</lastBuildDate><pubDate>Mon, 31 Aug 2009 01:44:37 GMT</pubDate><ttl>60</ttl><item><title>使用Visual Leak Detector检测内存泄漏</title><link>http://www.cppblog.com/iniwf/archive/2009/03/22/77465.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Sun, 22 Mar 2009 03:20:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/03/22/77465.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/77465.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/03/22/77465.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/77465.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/77465.html</trackback:ping><description><![CDATA[转自<a href="http://hi.baidu.com/freeze9527/blog/item/280742d15474983f9a502726.html">http://hi.baidu.com/freeze9527/blog/item/280742d15474983f9a502726.html</a><br><br>
<table style="TABLE-LAYOUT: fixed">
    <tbody>
        <tr>
            <td>
            <div class=cnt id=blog_text>原贴地址：　http://blog.csdn.net/dofty/archive/2006/09/07/1190606.aspx<br><br>
            <h1 style="MARGIN: 17pt 0cm 16.5pt"><span>初识</span><span><font face="Times New Roman">Visual Leak Detector</font></span></h1>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>灵活自由是</span><span><font face="Times New Roman">C/C++</font></span><span>语言的一大特色，而这也为</span><span><font face="Times New Roman">C/C++</font></span><span>程 序员出了一个难题。当程序越来越复杂时，内存的管理也会变得越加复杂，稍有不慎就会出现内存问题。内存泄漏是最常见的内存问题之一。内存泄漏如果不是很严 重，在短时间内对程序不会有太大的影响，这也使得内存泄漏问题有很强的隐蔽性，不容易被发现。然而不管内存泄漏多么轻微，当程序长时间运行时，其破坏力是 惊人的，从性能下降到内存耗尽，甚至会影响到其他程序的正常运行。另外内存问题的一个共同特点是，内存问题本身并不会有很明显的现象，当有异常现象出现时 已时过境迁，其现场已非出现问题时的现场了，这给调试内存问题带来了很大的难度。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span><font size=3><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font></font></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Visual Leak Detector</font></span><span>是一款用于</span><span><font face="Times New Roman">Visual C++</font></span><span>的免费的内存泄露检测工具。可以在</span><span><a href="http://www.codeproject.com/tools/visualleakdetector.asp"><font face="Times New Roman" color=#800080><u>http://www.codeproject.com/tools/visualleakdetector.asp</u></font></a><font face="Times New Roman"> </font></span><span>下载到。相比较其它的内存泄露检测工具，它在检测到内存泄漏的同时，还具有如下特点：</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt"><span><span><font face="Times New Roman"><font size=3>1、</font><span> </span></font></span></span><font size=3><span>可以得到内存泄漏点的调用堆栈，如果可以的话，还可以得到其所在文件及行号；</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt"><span><span><font face="Times New Roman"><font size=3>2、</font><span> </span></font></span></span><font size=3><span>可以得到泄露内存的完整数据；</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt"><span><span><font face="Times New Roman"><font size=3>3、</font><span> </span></font></span></span><font size=3><span>可以设置内存泄露报告的级别；</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt"><span><span><font face="Times New Roman"><font size=3>4、</font><span> </span></font></span></span><font size=3><span>它是一个已经打包的</span><span><font face="Times New Roman">lib</font></span><span>，使用时无须编译它的源代码。而对于使用者自己的代码，也只需要做很小的改动；</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt"><span><span><font face="Times New Roman"><font size=3>5、</font><span> </span></font></span></span><font size=3><span>他的源代码使用</span><span><font face="Times New Roman">GNU</font></span><span>许可发布，并有详尽的文档及注释。对于想深入了解堆内存管理的读者，是一个不错的选择。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span><font size=3><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font></font></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>可见，从使用角度来讲，</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>简单易用，对于使用者自己的代码，唯一的修改是</span><span><font face="Times New Roman">#include Visual Leak Detector</font></span><span>的头文件后正常运行自己的程序，就可以发现内存问题。从研究的角度来讲，如果深入</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>源代码，可以学习到堆内存分配与释放的原理、内存泄漏检测的原理及内存操作的常用技巧等。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>本文首先将介绍</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>的使用方法与步骤，然后再和读者一起初步的研究</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>的源代码，去了解</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>的工作原理。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span><font size=3></font></span></p>
            <h1 style="MARGIN: 17pt 0cm 16.5pt"><span>使用</span><span><font face="Times New Roman">Visual Leak Detector(1.0)</font></span></h1>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>下面让我们来介绍如何使用这个小巧的工具。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>首先从网站上下载</span><span><font face="Times New Roman">zip</font></span><span>包，解压之后得到</span><span><font face="Times New Roman">vld.h, vldapi.h, vld.lib, vldmt.lib, vldmtdll.lib, dbghelp.dll</font></span><span>等文件。将</span><span><font face="Times New Roman">.h</font></span><span>文件拷贝到</span><span><font face="Times New Roman">Visual C++</font></span><span>的默认</span><span><font face="Times New Roman">include</font></span><span>目录下，将</span><span><font face="Times New Roman">.lib</font></span><span>文件拷贝到</span><span><font face="Times New Roman">Visual C++</font></span><span>的默认</span><span><font face="Times New Roman">lib</font></span><span>目录下，便安装完成了。因为版本问题，如果使用</span><span><font face="Times New Roman">windows 2000</font></span><span>或者以前的版本，需要将</span><span><font face="Times New Roman">dbghelp.dll</font></span><span>拷贝到你的程序的运行目录下，或其他可以引用到的目录。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>接下来需要将其加入到自己的代码中。方法很简单，只要在包含入口函数的</span><span><font face="Times New Roman">.cpp</font></span><span>文件中包含</span><span><font face="Times New Roman">vld.h</font></span><span>就可以。如果这个</span><span><font face="Times New Roman">cpp</font></span><span>文件包含了</span><span><font face="Times New Roman">stdafx.h</font></span><span>，则将包含</span><span><font face="Times New Roman">vld.h</font></span><span>的语句放在</span><span><font face="Times New Roman">stdafx.h</font></span><span>的包含语句之后，否则放在最前面。如下是一个示例程序：</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt; COLOR: blue">#include</span><span style="FONT-SIZE: 9pt"> <span style="COLOR: maroon">&lt;vld.h&gt;</span></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt; COLOR: blue">void</span><span style="FONT-SIZE: 9pt"> main()</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt">{</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; TEXT-ALIGN: left" align=left><font face="Times New Roman"><span style="FONT-SIZE: 9pt">&#8230;</span><span style="FONT-SIZE: 9pt"></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 9pt">}</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>接下来让我们来演示如何使用</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>检测内存泄漏。下面是一个简单的程序，用</span><span><font face="Times New Roman">new</font></span><span>分配了一个</span><span><font face="Times New Roman">int</font></span><span>大小的堆内存，并没有释放。其申请的内存地址用</span><span><font face="Times New Roman">printf</font></span><span>输出到屏幕上。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt; COLOR: blue">#include</span><span style="FONT-SIZE: 9pt"> <span style="COLOR: maroon">&lt;vld.h&gt;</span></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt; COLOR: blue">#include</span><span style="FONT-SIZE: 9pt"> <span style="COLOR: maroon">&lt;stdlib.h&gt;</span></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt; COLOR: blue">#include</span><span style="FONT-SIZE: 9pt"> <span style="COLOR: maroon">&lt;stdio.h&gt;</span></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt; COLOR: maroon"></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt; COLOR: blue">void</span><span style="FONT-SIZE: 9pt"> f()</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt">{</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">int</span> *p = <span style="COLOR: blue">new</span> <span style="COLOR: blue">int</span>(0x12345678);</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span>printf(<span style="COLOR: maroon">"p=%08x, "</span>, p);</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt">}</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt; COLOR: blue">void</span><span style="FONT-SIZE: 9pt"> main()</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt">{</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span>f();</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt">}</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span>编译运行后，在标准输出窗口得到：</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span><font size=3><font face="Times New Roman">p=003a89c0</font></font></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span><font face="Times New Roman" size=3></font></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span>在</span><span><font face="Times New Roman">Visual C++</font></span><span>的</span><span><font face="Times New Roman">Output</font></span><span>窗口得到：</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt">WARNING: Visual Leak Detector detected memory leaks!</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt">---------- Block 57 at 0x003A89C0: 4 bytes ----------<span> </span><span style="COLOR: red">--57</span></span><span style="FONT-SIZE: 9pt; COLOR: red">号块<span>0x003A89C0</span>地址泄漏了<span>4</span>个字节</span><span style="FONT-SIZE: 9pt"></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span></span>Call Stack: <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: red"><span> </span>--</span></span><span style="FONT-SIZE: 9pt; COLOR: red">下面是调用堆栈</span><span style="FONT-SIZE: 9pt"></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span>d:\test\testvldconsole\testvldconsole\main.cpp (7): f<span> </span><span style="COLOR: red">--</span></span><span style="FONT-SIZE: 9pt; COLOR: red">表示在<span>main.cpp</span>第<span>7</span>行的<span>f()</span>函数</span><span style="FONT-SIZE: 9pt"></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span>d:\test\testvldconsole\testvldconsole\main.cpp (14): main </span><span style="FONT-SIZE: 9pt; COLOR: red"><font face="Times New Roman">&#8211;</font></span><span style="FONT-SIZE: 9pt; COLOR: red">双击以引导至对应代码处</span><span style="FONT-SIZE: 9pt"></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span>f:\rtm\vctools\crt_bld\self_x86\crt\src\crtexe.c (586): __tmainCRTStartup</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span>f:\rtm\vctools\crt_bld\self_x86\crt\src\crtexe.c (403): mainCRTStartup</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span>0x7C816D4F (File and line number not available): RegisterWaitForInputIdle</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span></span>Data: <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: red">--</span></span><span style="FONT-SIZE: 9pt; COLOR: red">这是泄漏内存的内容，<span>0x12345678</span></span><span style="FONT-SIZE: 9pt"></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span>78 56 34 12<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>xV4..... ........</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 9pt">Visual Leak Detector detected 1 memory leak.</span><span><font size=3><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp; </span></font></font></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font size=3><span>第二行表示</span><span><font face="Times New Roman">57</font></span><span>号块有</span><span><font face="Times New Roman">4</font></span><span>字节的内存泄漏，地址为</span><span><font face="Times New Roman">0x003A89C0</font></span><span>，根据程序控制台的输出，可以知道，该地址为指针</span><span><font face="Times New Roman">p</font></span><span>。程序的第</span><span><font face="Times New Roman">7</font></span><span>行，</span><span><font face="Times New Roman">f()</font></span><span>函数里，在该地址处分配了</span><span><font face="Times New Roman">4</font></span><span>字节的堆内存空间，并赋值为</span><span><font face="Times New Roman">0x12345678</font></span><span>，这样在报告中，我们看到了这</span><span><font face="Times New Roman">4</font></span><span>字节同样的内容。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font size=3><span>可以看出，对于每一个内存泄漏，这个报告列出了它的泄漏点、长度、分配该内存时的调用堆栈、和泄露内存的内容（分别以</span><span><font face="Times New Roman">16</font></span><span>进制和文本格式列出）。双击该堆栈报告的某一行，会自动在代码编辑器中跳到其所指文件的对应行。这些信息对于我们查找内存泄露将有很大的帮助。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font size=3><span>这是一个很方便易用的工具，安装后每次使用时，仅仅需要将它头文件包含进来重新</span><span><font face="Times New Roman">build</font></span><span>就可以。而且，该工具仅在</span><span><font face="Times New Roman">build Debug</font></span><span>版的时候会连接到你的程序中，如果</span><span><font face="Times New Roman">build Release</font></span><span>版，该工具不会对你的程序产生任何性能等方面影响。所以尽可以将其头文件一直包含在你的源代码中。</span><span></span></font></p>
            <h1 style="MARGIN: 17pt 0cm 16.5pt"><span><font face="Times New Roman">Visual Leak Detector</font></span><span>工作原理</span></h1>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>下面让我们来看一下该工具的工作原理。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>在这之前，我们先来看一下</span><span><font face="Times New Roman">Visual C++</font></span><span>内置的内存泄漏检测工具是如何工作的。</span><span><font face="Times New Roman">Visual C++</font></span><span>内置的工具</span><span><font face="Times New Roman">CRT Debug Heap</font></span><span>工作原来很简单。在使用</span><span><font face="Times New Roman">Debug</font></span><span>版的</span><span><font face="Times New Roman">malloc</font></span><span>分配内存时，</span><span><font face="Times New Roman">malloc</font></span><span>会在内存块的头中记录分配该内存的文件名及行号。当程序退出时</span><span><font face="Times New Roman">CRT</font></span><span>会在</span><span><font face="Times New Roman">main()</font></span><span>函数返回之后做一些清理工作，这个时候来检查调试堆内存，如果仍然有内存没有被释放，则一定是存在内存泄漏。从这些没有被释放的内存块的头中，就可以获得文件名及行号。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>这种静态的方法可以检测出内存泄漏及其泄漏点的文件名和行号，但是并不知道泄漏究竟是如何发生的，并不知道该内存分配语句是如何被执行到的。要想了解这些，就必须要对程序的内存分配过程进行动态跟踪。</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>就是这样做的。它在每次内存分配时将其上下文记录下来，当程序退出时，对于检测到的内存泄漏，查找其记录下来的上下文信息，并将其转换成报告输出。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span><font size=3><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font></font></span></p>
            <h2 style="MARGIN: 13pt 0cm"><span>初始化</span></h2>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Visual Leak Detector</font></span><span>要记录每一次的内存分配，而它是如何监视内存分配的呢？</span><span><font face="Times New Roman">Windows</font></span><span>提供了分配钩子</span><span><font face="Times New Roman">(allocation hooks)</font></span><span>来监视调试堆内存的分配。它是一个用户定义的回调函数，在每次从调试堆分配内存之前被调用。在初始化时，</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>使用</span></font><span style="FONT-SIZE: 9pt">_CrtSetAllocHook</span><font size=3><span>注册这个钩子函数，这样就可以监视从此之后所有的堆内存分配了。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>如何保证在</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>初始化之前没有堆内存分配呢？全局变量是在程序启动时就初始化的，如果将</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>作为一个全局变量，就可以随程序一起启动。但是</span><span><font face="Times New Roman">C/C++</font></span><span>并没有约定全局变量之间的初始化顺序，如果其它全局变量的构造函数中有堆内存分配，则可能无法检测到。</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>使用了</span><span><font face="Times New Roman">C/C++</font></span><span>提供的</span><span><font face="Times New Roman">#pragma init_seg</font></span><span>来在某种程度上减少其它全局变量在其之前初始化的概率。根据</span><span><font face="Times New Roman">#pragma init_seg</font></span><span>的定义，全局变量的初始化分三个阶段：首先是</span><span><font face="Times New Roman">compiler</font></span><span>段，一般</span><span><font face="Times New Roman">c</font></span><span>语言的运行时库在这个时候初始化；然后是</span><span><font face="Times New Roman">lib</font></span><span>段，一般用于第三方的类库的初始化等；最后是</span><span><font face="Times New Roman">user</font></span><span>段，大部分的初始化都在这个阶段进行。</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>将其初始化设置在</span><span><font face="Times New Roman">compiler</font></span><span>段，从而使得它在绝大多数全局变量和几乎所有的用户定义的全局变量之前初始化。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span><font face="Times New Roman" size=3></font></span></p>
            <h2 style="MARGIN: 13pt 0cm"><span>记录内存分配</span></h2>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>一个分配钩子函数需要具有如下的形式：</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt; COLOR: blue">int</span><span style="FONT-SIZE: 9pt"> YourAllocHook( <span style="COLOR: blue">int</span> allocType, <span style="COLOR: blue">void</span> *userData, size_t size, <span style="COLOR: blue">int</span> blockType, <span style="COLOR: blue">long</span> requestNumber, <span style="COLOR: blue">const</span> <span style="COLOR: blue">unsigned</span> <span style="COLOR: blue">char</span> *filename, <span style="COLOR: blue">int</span> lineNumber);</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>就像前面说的，它在</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>初始化时被注册，每次从调试堆分配内存之前被调用。这个函数需要处理的事情是记录下此时的调用堆栈和此次堆内存分配的唯一标识——</span></font><span style="FONT-SIZE: 9pt">requestNumber</span><font size=3><span>。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>得到当前的堆栈的二进制表示并不是一件很复杂的事情，但是因为不同体系结构、不同编译器、不同的函数调用约定所产生的堆栈内容略有不同，要解释堆栈并得到整个函数调用过程略显复杂。不过</span><span><font face="Times New Roman">windows</font></span><span>提供一个</span><span><font face="Times New Roman">StackWalk64</font></span><span>函数，可以获得堆栈的内容。</span><span><font face="Times New Roman">StackWalk64</font></span><span>的声明如下：</span><span></span></font></p>
            <pre><font style="BACKGROUND-COLOR: rgb(221,221,221)"><strong><span style="FONT-SIZE: 8.5pt">BOOL</span></strong><span style="FONT-SIZE: 8.5pt"> <strong>StackWalk64(</strong></span></font></pre>
            <pre><span style="FONT-SIZE: 8.5pt"><font style="BACKGROUND-COLOR: rgb(221,221,221)"><span>  </span><strong>DWORD</strong> <em><span><span class=MsoHyperlink><span style="COLOR: rgb(0,64,255); TEXT-DECORATION: none"><u>MachineType</u></span></span></span></em><strong>,</strong></font></span></pre>
            <pre><span style="FONT-SIZE: 8.5pt"><font style="BACKGROUND-COLOR: rgb(221,221,221)"><span>  </span><strong>HANDLE</strong> <em><span><span class=MsoHyperlink><span style="COLOR: rgb(0,64,255); TEXT-DECORATION: none"><u>hProcess</u></span></span></span></em><strong>,</strong></font></span></pre>
            <pre><span style="FONT-SIZE: 8.5pt"><font style="BACKGROUND-COLOR: rgb(221,221,221)"><span>  </span><strong>HANDLE</strong> <em><span><span class=MsoHyperlink><span style="COLOR: rgb(0,64,255); TEXT-DECORATION: none"><u>hThread</u></span></span></span></em><strong>,</strong></font></span></pre>
            <pre><span style="FONT-SIZE: 8.5pt"><font style="BACKGROUND-COLOR: rgb(221,221,221)"><span>  </span><strong>LPSTACKFRAME64</strong> <em><span><span class=MsoHyperlink><span style="COLOR: rgb(0,64,255); TEXT-DECORATION: none"><u>StackFrame</u></span></span></span></em><strong>,</strong></font></span></pre>
            <pre><span style="FONT-SIZE: 8.5pt"><font style="BACKGROUND-COLOR: rgb(221,221,221)"><span>  </span><strong>PVOID</strong> <em><span><span class=MsoHyperlink><span style="COLOR: rgb(0,64,255); TEXT-DECORATION: none"><u>ContextRecord</u></span></span></span></em><strong>,</strong></font></span></pre>
            <pre><span style="FONT-SIZE: 8.5pt"><font style="BACKGROUND-COLOR: rgb(221,221,221)"><span>  </span><strong>PREAD_PROCESS_MEMORY_ROUTINE64</strong> <em><span><span class=MsoHyperlink><span style="COLOR: rgb(0,64,255); TEXT-DECORATION: none"><u>ReadMemoryRoutine</u></span></span></span></em><strong>,</strong></font></span></pre>
            <pre><span style="FONT-SIZE: 8.5pt"><font style="BACKGROUND-COLOR: rgb(221,221,221)"><span>  </span><strong>PFUNCTION_TABLE_ACCESS_ROUTINE64</strong> <em><span><span class=MsoHyperlink><span style="COLOR: rgb(0,64,255); TEXT-DECORATION: none"><u>FunctionTableAccessRoutine</u></span></span></span></em><strong>,</strong></font></span></pre>
            <pre><span style="FONT-SIZE: 8.5pt"><font style="BACKGROUND-COLOR: rgb(221,221,221)"><span>  </span><strong>PGET_MODULE_BASE_ROUTINE64</strong> <em><span><span class=MsoHyperlink><span style="COLOR: rgb(0,64,255); TEXT-DECORATION: none"><u>GetModuleBaseRoutine</u></span></span></span></em><strong>,</strong></font></span></pre>
            <pre><span style="FONT-SIZE: 8.5pt"><font style="BACKGROUND-COLOR: rgb(221,221,221)"><span>  </span><strong>PTRANSLATE_ADDRESS_ROUTINE64</strong> <u><em><span><span class=MsoHyperlink><span style="COLOR: rgb(0,64,255); TEXT-DECORATION: none">TranslateAddress</span></span></span></em><strong></strong></u></font></span></pre>
            <pre><font style="BACKGROUND-COLOR: rgb(221,221,221)"><strong><span style="FONT-SIZE: 8.5pt">);</span></strong><span style="FONT-SIZE: 8.5pt"></span></font></pre>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><font face="Times New Roman">STACKFRAME64</font></span><span>结构表示了堆栈中的一个</span><span><font face="Times New Roman">frame</font></span><span>。给出初始的</span><span><font face="Times New Roman">STACKFRAME64</font></span><span>，反复调用该函数，便可以得到内存分配点的调用堆栈了。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span><span style="COLOR: green">// Walk the stack.</span></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">while</span> (count &lt; _VLD_maxtraceframes) {</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>count++;</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">if</span> (!pStackWalk64(architecture, m_process, m_thread, &amp;frame, &amp;context,</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span></span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>NULL, pSymFunctionTableAccess64, pSymGetModuleBase64, NULL)) {</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: green">// Couldn't trace back through any more frames.</span></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">break</span>;</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">if</span> (frame.AddrFrame.Offset == 0) {</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: green">// End of stack.</span></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: blue">break</span>;</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: green">// Push this frame's program counter onto the provided CallStack.</span></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>callstack-&gt;push_back((DWORD_PTR)frame.AddrPC.Offset);</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span>}</span><span></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>那么，如何得到初始的</span><span><font face="Times New Roman">STACKFRAME64</font></span><span>结构呢？在</span><span><font face="Times New Roman">STACKFRAME64</font></span><span>结构中，其他的信息都比较容易获得，而当前的程序计数器</span><span><font face="Times New Roman">(EIP)</font></span><span>在</span><span><font face="Times New Roman">x86</font></span><span>体系结构中无法通过软件的方法直接读取。</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>使用了一种方法来获得当前的程序计数器。首先，它调用一个函数，则这个函数的返回地址就是当前的程序计数器，而函数的返回地址可以很容易的从堆栈中拿到。下面是</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>获得当前程序计数器的程序：</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt; COLOR: blue">#if</span><span style="FONT-SIZE: 9pt"> <span style="COLOR: blue">defined</span>(_M_IX86) || <span style="COLOR: blue">defined</span>(_M_X64)</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt; COLOR: blue">#pragma</span><span style="FONT-SIZE: 9pt"> <span style="COLOR: blue">auto_inline</span>(<span style="COLOR: blue">off</span>)</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt">DWORD_PTR VisualLeakDetector::getprogramcounterx86x64 ()</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt">{</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span>DWORD_PTR programcounter;</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">__asm</span> mov AXREG, [BPREG + SIZEOFPTR] <span style="COLOR: green">// Get the return address out of the current stack frame</span></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">__asm</span> mov [programcounter], AXREG<span>&nbsp;&nbsp;&nbsp; </span><span style="COLOR: green">// Put the return address into the variable we'll return</span></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt; COLOR: green"></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">return</span> programcounter;</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt">}</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt; COLOR: blue">#pragma</span><span style="FONT-SIZE: 9pt"> <span style="COLOR: blue">auto_inline</span>(<span style="COLOR: blue">on</span>)</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 9pt; COLOR: blue">#endif</span><span style="FONT-SIZE: 9pt"> <span style="COLOR: green">// defined(_M_IX86) || defined(_M_X64)</span></span><span></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>得到了调用堆栈，自然要记录下来。</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>使用一个类似</span><span><font face="Times New Roman">map</font></span><span>的数据结构来记录该信息。这样可以方便的从</span></font><span style="FONT-SIZE: 9pt">requestNumber</span><span><font size=3>查找到其调用堆栈。分配钩子函数的</font></span><span style="FONT-SIZE: 9pt">allocType</span><font size=3><span>参数表示此次堆内存分配的类型，包括</span><span><font face="Times New Roman">_HOOK_ALLOC, _HOOK_REALLOC, </font></span><span>和</span><span><font face="Times New Roman"> _HOOK_FREE</font></span><span>，下面代码是</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>对各种情况的处理。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span><font face="Times New Roman" size=3></font></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">switch</span> (type) {</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">case</span> _HOOK_ALLOC:</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>visualleakdetector.hookmalloc(request);</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">break</span>;</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">case</span> _HOOK_FREE:</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>visualleakdetector.hookfree(pdata);</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">break</span>;</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">case</span> _HOOK_REALLOC:</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>visualleakdetector.hookrealloc(pdata, request);</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">break</span>;</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">default</span>:</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>visualleakdetector.report(<span style="COLOR: maroon">"WARNING: Visual Leak Detector: in allochook(): Unhandled allocation type (%d).\n"</span>, type);</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">break</span>;</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span>}</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span>这里，</span><span><font face="Times New Roman">hookmalloc()</font></span><span>函数得到当前堆栈，并将当前堆栈与</span><span><font face="Times New Roman">requestNumber</font></span><span>加入到类似</span><span><font face="Times New Roman">map</font></span><span>的数据结构中。</span><span><font face="Times New Roman">hookfree()</font></span><span>函数从类似</span><span><font face="Times New Roman">map</font></span><span>的数据结构中删除该信息。</span><span><font face="Times New Roman">hookrealloc()</font></span><span>函数依次调用了</span><span><font face="Times New Roman">hookfree()</font></span><span>和</span><span><font face="Times New Roman">hookmalloc()</font></span><span>。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span><font face="Times New Roman" size=3></font></span></p>
            <h2 style="MARGIN: 13pt 0cm"><span>检测内存泄露</span></h2>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>前面提到了</span><span><font face="Times New Roman">Visual C++</font></span><span>内置的内存泄漏检测工具的工作原理。与该原理相同，因为全局变量以构造的相反顺序析构，在</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>析构时，几乎所有的其他变量都已经析构，此时如果仍然有未释放之堆内存，则必为内存泄漏。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>分配的堆内存是通过一个链表来组织的，检查内存泄漏则是检查此链表。但是</span><span><font face="Times New Roman">windows</font></span><span>没有提供方法来访问这个链表。</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>使用了一个小技巧来得到它。首先在堆上申请一块临时内存，则该内存的地址可以转换成指向一个</span><span><font face="Times New Roman">_CrtMemBlockHeader</font></span><span>结构，在此结构中就可以获得这个链表。代码如下：</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">char</span> *pheap = <span style="COLOR: blue">new</span> <span style="COLOR: blue">char</span>;</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp; </span>_CrtMemBlockHeader *pheader = pHdr(pheap)-&gt;pBlockHeaderNext;</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 18pt"><span style="FONT-SIZE: 9pt; COLOR: blue">delete</span><span style="FONT-SIZE: 9pt"> pheap;</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span>其中</span><span><font face="Times New Roman">pheader</font></span><span>则为链表首指针。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span><font face="Times New Roman" size=3></font></span></p>
            <h2 style="MARGIN: 13pt 0cm"><span>报告生成</span></h2>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>前面讲了</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>如何检测、记录内存泄漏及其其调用堆栈。但是如果要这个信息对程序员有用的话，必须转换成可读的形式。</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>使用</span><span><font face="Times New Roman">SymGetLineFromAddr64()</font></span><span>及</span><span><font face="Times New Roman">SymFromAddr()</font></span><span>生成可读的报告。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: green">// Iterate through each frame in the call stack.</span></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">for</span> (frame = 0; frame &lt; callstack-&gt;size(); frame++) {</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: green">// Try to get the source file and line number associated with</span></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: green">// this program counter address.</span></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">if</span> (pSymGetLineFromAddr64(m_process, </span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>(*callstack)[frame], &amp;displacement, &amp;sourceinfo)) {</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>...</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: green">// Try to get the name of the function containing this program</span></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: green">// counter address.</span></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">if</span> (pSymFromAddr(m_process, (*callstack)[frame], </span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&amp;displacement64, pfunctioninfo)) {</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>functionname = pfunctioninfo-&gt;Name;</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: blue">else</span> {</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>functionname = <span style="COLOR: maroon">"(Function name unavailable)"</span>;</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>...</span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 9pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span><span></span></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>概括讲来，</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>的工作分为</span><span><font face="Times New Roman">3</font></span><span>步，首先在初始化注册一个钩子函数；然后在内存分配时该钩子函数被调用以记录下当时的现场；最后检查堆内存分配链表以确定是否存在内存泄漏并将泄漏内存的现场转换成可读的形式输出。有兴趣的读者可以阅读</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>的源代码。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span><font face="Times New Roman" size=3></font></span></p>
            <h1 style="MARGIN: 17pt 0cm 16.5pt"><span>总结</span></h1>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span></span><span>在使用上，</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>简单方便，结果报告一目了然。在原理上，</span><span><font face="Times New Roman">Visual Leak Detector</font></span><span>针 对内存泄漏问题的特点，可谓对症下药——内存泄漏不是不容易发现吗？那就每次内存分配是都给记录下来，程序退出时算总账；内存泄漏现象出现时不是已时过境 迁，并非当时泄漏点的现场了吗？那就把现场也记录下来，清清楚楚的告诉使用者那块泄漏的内存就是在如何一个调用过程中泄漏掉的。</span><span></span></font></p>
            <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><font size=3><span><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Visual Leak Detector</font></span><span>是一个简单易用内存泄漏检测工具。现在最新的版本是</span><span><font face="Times New Roman">1.9a</font></span><span>，采用了新的检测机制，并在功能上有了很多改进。读者不妨体验一下。</span></font><span></span></p>
            </div>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/iniwf/aggbug/77465.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-03-22 11:20 <a href="http://www.cppblog.com/iniwf/archive/2009/03/22/77465.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>