认识VLD

VLD(Visual Leak Detector)是一款用于Visual C++的开源内存泄漏检测工具,我们只需要在被检测内存泄漏的工程代码里#include “vld.h”就可以开启内存泄漏检测功能。当我们使用Visual Studio debugger来调试我们的进程时,VLD可以在程序退出时很直观地将泄漏的内存地址、堆栈、大小、内容输出到Visual Studio的Output窗口,此时我们只需要直接双击调用堆栈就可以跳转到对应的代码行,从而直接明了的知道哪里分配了的内存没有被释放,如下图:

本文要剖析的VLD版本是V2.3,其源码可以在http://vld.codeplex.com/下载到。

VLD原理概述

从本质上来说,VLD是通过监控所有内存操作(分配和释放)来检测内存泄漏的,而监控内存操作的方式也有很多种,比如Hook所有内存操作函数到自定义的函数中,或者通过修改IAT(Import Address Table导入地址表)来将原本要调用的内存操作函数修改为VLD自已的函数。这里VLD 的方法是后者。

VLD原理剖析

从#include “vld.h”开始看去

1.         首先我们在vld.h文件里可以看到#if defined _DEBUG || defined VLD_FORCE_ENABLE,这里表示的意思是Debug版本是默认开启监控的,但如果使用的是Release版本的话就需要在工程设置里加上VLD_FORCE_ENABLE预定义宏内存监控才会生效,这点也是需要提醒各位看官的。

2.         再者我们看到可以看到#pragma comment(lib, "vld.lib")这行代码。其实vld工程本身是一个dll工程,但dll工程编译时同时也会生成一个lib,通过这行代码我们的程序就不需要手动调用LoadLibrary来加载dll了。

3.         再者我们可以看到这样一段代码:

大概的意思就是导出一个对象(这个对象的名字叫g_vld,它是vld.cpp里的一个全局变量)为我们的程序所看到,从而保证vld.dll会被加载,不然编译器可能会认为vld.dll里我们的代码并没有依赖vld从而给优化掉了。这样,当vld.dll被加载时,这个对象就会被初始化,从而修改各dll的导入地址表来做监控所有内存操作。

从g_vld对象看VLD如何监控所有内存操作

1.         我们在vld.cpp里可以看到这个对象的定义,它是类VisualLeakDetector的实例,当此对象被初始化时会调用类的构造函数,接下来我们看看构造函数里做了什么事。

2.         首先,我们看看下面这段代码:

这里枚举了所有已加载的模块,然后再对枚举到的模块调用attachToLoadedModules,接下来我们看看attachToLoadedModules做了什么事情。

3.         在attachToLoadedModules函数里,它会枚举所有的模块,并调用下面这行代码:

这个函数的主要工作就是修改moduleBase所指示的模块的导入地址表,下面我看看传入参数m_patchTable是什么。

4.         可以看到m_patchTable是一个moduleentry_t数组,moduleentry_t的定义(在utility.h文件里)如下:

它的第一个成员exportModuleName表示的是一个dll的名字,第二个成员moduleBase表示的是该dll的基地址,第三个参数patchTable是一个结构体的指针,我们再看看patchentry_t的定义(在utility.h文件里):

其中importName是api的名字,这些API都内存操作相关的API,original表示的是该API的函数地址,replacement是VLD内部一个函数的地址,它是用来替换原来的函数地址的。

5.         接下来看看m_patchTable的具体内容(部分)吧:

再取其中的m_kernel32Patch看看其具体内容:

6.         通过代码可以发现PatchModule函数拿到上面的内存后,会对m_patchTable数组里的每一个元素调用PatchImport函数,而PatchImport就是真正修改导入地址表的地方。

看VLD如何管理监控到的内存

1.         所有内存分配最终都会调用kernel32的HeapAlloc以及HeapReAlloc函数,而前文的介绍中已经提到这两个函数会被VLD内部函数通过修改导入地址表而替换。各位看官看到这里可能会问:“既然所有内存分配最终都会走到这里,那为什么不直接监控这几个函数呢?为什么还要监控那么多其他函数(malloc,new,realloc,calloc等等)?”我的理解是:为了获取调用malloc,new,realloc,calloc这些函数时的堆栈。虽然从HeapAlloc开始回溯堆栈也没有什么问题,但VLD这不是为了美观么,不想有多余的干扰信息。

2.         VLD监控到分配的内存后会保存到一个map结构中:

这里以堆句柄为first key,second是一个结构体heapinfo_t,定义如下:

这里的成员blockMap又是一个map:

BlockMap以分配的内存地址为first key,然后second又是一个结构体,定义如下:

这里保存了所监控到的内存分配堆栈、分配序号、大小等信息。

3.         有了这个map结构后,当有内存被分配时,就会向这个map插入元素;而当有内存被释放时,就会从这个map中删除对应的元素。

4.         最后,当程序退出时,g_vld对象会被析构,此时map中的所有元素就是没有被释放的内存,也就是泄漏的内存。

总结

以上就是VLD的基本原理了,其实在VLD早前的版本中它并不是用的这种修改导入地址表的机制,这里就不再赘述了。总的来说,VLD还是一款简单易用的内存泄漏检测工具,但是它也有自已的缺陷:需要修改源程序的代码。这就使得需要有代码的情况下才能够检查内存泄漏,但对于测试人员来说,有时我们拿到的只是编译好的二进制,情况好点的话会有PDB,此时如何去检查内存泄漏也是一个值得研究的方向。

Visual Leak Detector原理剖析的更多相关文章

  1. 使用Visual Leak Detector检测内存泄漏[转]

      1.初识Visual Leak Detector 灵活自由是C/C++语言的一大特色,而这也为C/C++程序员出了一个难题.当程序越来越复杂时,内存的管理也会变得越加复杂,稍有不慎就会出现内存问题 ...

  2. vld(Visual Leak Detector) 内存泄露检测工具

    初识Visual Leak Detector 灵活自由是C/C++语言的一大特色,而这也为C/C++程序员出了一个难题.当程序越来越复 杂时,内存的管理也会变得越加复杂,稍有不慎就会出现内存问题.内存 ...

  3. 使用Visual Leak Detector for Visual C++ 捕捉内存泄露

    什么是内存泄漏? 内存泄漏(memory leak),指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况.内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段 ...

  4. Cocos开发中性能优化工具介绍之Visual Studio内存泄漏检测工具——Visual Leak Detector

    那么在Windows下有什么好的内存泄漏检测工具呢?微软提供Visual Studio开发工具本身没有什么太好的内存泄漏检测功能,我们可以使用第三方工具Visual Leak Detector(以下简 ...

  5. Visual Leak Detector 2.2.3 Visual C++内存检测工具

      Visual Leak Detector是一款免费的.健全的.开源的Visual C++内存泄露检测系统.相比Visual C++自带的内存检测机制,Visual Leak Detector可以显 ...

  6. Cocos性能优化工具的开发介绍Visual Studio内存泄漏检测工具——Visual Leak Detector

    然后,Windows下有什么好的内存泄漏检測工具呢?微软提供Visual Studio开发工具本身没有什么太好的内存泄漏检測功能.我们能够使用第三方工具Visual Leak Detector(下面简 ...

  7. VisualStudio 怎么使用Visual Leak Detector

    VisualStudio 怎么使用Visual Leak Detector 那么在Windows下有什么好的内存泄漏检测工具呢?微软提供Visual Studio开发工具本身没有什么太好的内存泄漏检测 ...

  8. Visual Leak Detector简明使用教程

    Visual Leak Detector是一款内存泄漏检测软件,主要的作用就是检测可能或者是存在内存泄露的地方,具体的功能的话,可以百度下,今天主要简单介绍下怎么使用 首先下载Visual Leak ...

  9. VS2017 编译 Visual Leak Detector + VLD 使用示例

    起因 一个Qt5+VS2017的工程,需要进行串口操作,在自动时发现一段时间软件崩溃了,没有保存log,在 debug 的时候发现每运行一次应用占据的内存就多一点,后来意识到是内存泄漏了.这个真是头疼 ...

随机推荐

  1. Scrum Meeting Beta - 7

    Scrum Meeting Beta - 7 NewTeam 2017/12/6 地点:新主楼F座二楼 任务反馈 团队成员 完成任务 计划任务 安万贺 修复离线状态下启动时的bugIssue #150 ...

  2. 项目复审—Alpha阶段

    项目复审-Alpha阶段 小组的名字和链接 优 点 缺 点 排名 [别看了你没救队]http://www.cnblogs.com/liaoyujun233/p/9016362.html 此队优点很多, ...

  3. 累计进度条 PSP 饼图

    累计进度条   PSP   饼图 每周例行报告 本周PSP 类别 任务 开始时间 结束时间 被打断时间 总计工作时间 2016年9月24日 读书 构建之法-6.7章 19:00 20:00 2 58m ...

  4. mysql DDL、DML、DCL、DQL区分

    mysql [Structure Query Language] 的组成分4个部分: DDL     [Data Mefinition Language]    数据定义语言 DML    [Data ...

  5. vue 引入组件

    <comA></comA>此时可用在模板里 //a为vue文件,里面定义了模板import comA from './components/a' export default ...

  6. 本地存储—localStorage(HTML5)

    https://my.oschina.net/jgy/blog/99631 localStorage简介 今夜死活睡不着,决定整理下最近搞得localStorage…… 先简单说下阐述下:localS ...

  7. WEB javaScript

    javaScript 1.常规方法document.write("内容") :书写内容到网页中window.alert("内容") :网页警告弹窗 2.使用方法 ...

  8. 【NOIP&NOI】飞扬的小鸟 Flappy Bird

    描述 Flappy Bird 是一款风靡一时的休闲手机游戏.玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙.如果小鸟一不小心撞到了水管或者掉在地上的话,便宣告 ...

  9. AC自动机【萌新文章】

    我这个蒟蒻第一次写博客,有点小激动呢. 主要是最近刚学了AC自动机,学得糟糟糕糕,记录一下,看到dalao们都在写博客,决定自己也写一波[我好水的啦,写的也不好] AC自动机大概就是    Trie+ ...

  10. 【django基础之ORM,增删改查】

    一.定义 1.什么是ORM? ORM,即Object-Relational Mapping(对象关系映射),它的作用是在关系型数据库和业务实体对象之间作一个映射,这样,我们在具体的操作业务对象的时候, ...