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

时间:2022-09-09 18:53:00
 

1.初识Visual Leak Detector

灵活*是C/C++语言的一大特色,而这也为C/C++程序员出了一个难题。当程序越来越复杂时,内存的管理也会变得越加复杂,稍有不慎就会出现内存问题。内存泄漏是最常见的内存问题之一。内存泄漏如果不是很严重,在短时间内对程序不会有太大的影响,这也使得内存泄漏问题有很强的隐蔽性,不容易被发现。然而不管内存泄漏多么轻微,当程序长时间运行时,其破坏力是惊人的,从性能下降到内存耗尽,甚至会影响到其他程序的正常运行。另外内存问题的一个共同特点是,内存问题本身并不会有很明显的现象,当有异常现象出现时已时过境迁,其现场已非出现问题时的现场了,这给调试内存问题带来了很大的难度。

Visual Leak Detector是一款用于Visual C++的免费的内存泄露检测工具。可以在http://www.codeproject.com/tools/visualleakdetector.asp下载到。相比较其它的内存泄露检测工具,它在检测到内存泄漏的同时,还具有如下特点:

1、 可以得到内存泄漏点的调用堆栈,如果可以的话,还可以得到其所在文件及行号;

2、 可以得到泄露内存的完整数据;

3、 可以设置内存泄露报告的级别;

4、 它是一个已经打包的lib,使用时无须编译它的源代码。而对于使用者自己的代码,也只需要做很小的改动;

5、 他的源代码使用GNU许可发布,并有详尽的文档及注释。对于想深入了解堆内存管理的读者,是一个不错的选择。

可见,从使用角度来讲,Visual Leak Detector简单易用,对于使用者自己的代码,唯一的修改是#include Visual Leak Detector的头文件后正常运行自己的程序,就可以发现内存问题。从研究的角度来讲,如果深入Visual Leak Detector源代码,可以学习到堆内存分配与释放的原理、内存泄漏检测的原理及内存操作的常用技巧等。

本文首先将介绍Visual Leak Detector的使用方法与步骤,然后再和读者一起初步的研究Visual Leak Detector的源代码,去了解Visual Leak Detector的工作原理。

2.使用Visual Leak Detector(1.0)

下面让我们来介绍如何使用这个小巧的工具。

首先从网站上下载zip包,解压之后得到vld.h, vldapi.h, vld.lib, vldmt.lib, vldmtdll.lib, dbghelp.dll等文件。将.h文件拷贝到Visual C++的默认include目录下,将.lib文件拷贝到Visual C++的默认lib目录下,便安装完成了。因为版本问题,如果使用windows 2000或者以前的版本,需要将dbghelp.dll拷贝到你的程序的运行目录下,或其他可以引用到的目录。

接下来需要将其加入到自己的代码中。方法很简单,只要在包含入口函数的.cpp文件中包含vld.h就可以。如果这个cpp文件包含了stdafx.h,则将包含vld.h的语句放在stdafx.h的包含语句之后,否则放在最前面。如下是一个示例程序:

#include<vld.h>

voidmain()

{

}

接下来让我们来演示如何使用Visual Leak Detector检测内存泄漏。下面是一个简单的程序,用new分配了一个int大小的堆内存,并没有释放。其申请的内存地址用printf输出到屏幕上。

#include<vld.h>

#include<stdlib.h>

#include<stdio.h>

voidf()

{

int*p =newint(0x12345678);

printf("p=%08x, ", p);

}

voidmain()

{

f();

}

编译运行后,在标准输出窗口得到:

p=003a89c0

在Visual C++的Output窗口得到:

WARNING: Visual Leak Detector detected memory leaks!

---------- Block 57 at 0x003A89C0: 4 bytes ---------- --57号块0x003A89C0地址泄漏了4个字节

Call Stack:                                             --下面是调用堆栈

d:\test\testvldconsole\testvldconsole\main.cpp (7): f --表示在main.cpp第7行的f()函数

d:\test\testvldconsole\testvldconsole\main.cpp (14): main–双击以引导至对应代码处

f:\rtm\vctools\crt_bld\self_x86\crt\src\crtexe.c (586): __tmainCRTStartup

f:\rtm\vctools\crt_bld\self_x86\crt\src\crtexe.c (403): mainCRTStartup

0x7C816D4F (File and line number not available): RegisterWaitForInputIdle

Data:                                 --这是泄漏内存的内容,0x12345678

78 56 34 12                                                 xV4..... ........

Visual Leak Detector detected 1 memory leak.

第二行表示57号块有4字节的内存泄漏,地址为0x003A89C0,根据程序控制台的输出,可以知道,该地址为指针p。程序的第7行,f()函数里,在该地址处分配了4字节的堆内存空间,并赋值为0x12345678,这样在报告中,我们看到了这4字节同样的内容。

可以看出,对于每一个内存泄漏,这个报告列出了它的泄漏点、长度、分配该内存时的调用堆栈、和泄露内存的内容(分别以16进制和文本格式列出)。双击该堆栈报告的某一行,会自动在代码编辑器中跳到其所指文件的对应行。这些信息对于我们查找内存泄露将有很大的帮助。

这是一个很方便易用的工具,安装后每次使用时,仅仅需要将它头文件包含进来重新build就可以。而且,该工具仅在build Debug版的时候会连接到你的程序中,如果build Release版,该工具不会对你的程序产生任何性能等方面影响。所以尽可以将其头文件一直包含在你的源代码中。

3.Visual Leak Detector工作原理

下面让我们来看一下该工具的工作原理。

在这之前,我们先来看一下Visual C++内置的内存泄漏检测工具是如何工作的。Visual C++内置的工具CRT Debug Heap工作原来很简单。在使用Debug版的malloc分配内存时,malloc会在内存块的头中记录分配该内存的文件名及行号。当程序退出时CRT会在main()函数返回之后做一些清理工作,这个时候来检查调试堆内存,如果仍然有内存没有被释放,则一定是存在内存泄漏。从这些没有被释放的内存块的头中,就可以获得文件名及行号。

这种静态的方法可以检测出内存泄漏及其泄漏点的文件名和行号,但是并不知道泄漏究竟是如何发生的,并不知道该内存分配语句是如何被执行到的。要想了解这些,就必须要对程序的内存分配过程进行动态跟踪。Visual Leak Detector就是这样做的。它在每次内存分配时将其上下文记录下来,当程序退出时,对于检测到的内存泄漏,查找其记录下来的上下文信息,并将其转换成报告输出。

3.1初始化

Visual Leak Detector要记录每一次的内存分配,而它是如何监视内存分配的呢?Windows提供了分配钩子(allocation hooks)来监视调试堆内存的分配。它是一个用户定义的回调函数,在每次从调试堆分配内存之前被调用。在初始化时,Visual Leak Detector使用_CrtSetAllocHook注册这个钩子函数,这样就可以监视从此之后所有的堆内存分配了。

如何保证在Visual Leak Detector初始化之前没有堆内存分配呢?全局变量是在程序启动时就初始化的,如果将Visual Leak Detector作为一个全局变量,就可以随程序一起启动。但是C/C++并没有约定全局变量之间的初始化顺序,如果其它全局变量的构造函数中有堆内存分配,则可能无法检测到。Visual Leak Detector使用了C/C++提供的#pragma init_seg来在某种程度上减少其它全局变量在其之前初始化的概率。根据#pragma init_seg的定义,全局变量的初始化分三个阶段:首先是compiler段,一般c语言的运行时库在这个时候初始化;然后是lib段,一般用于第三方的类库的初始化等;最后是user段,大部分的初始化都在这个阶段进行。Visual Leak Detector将其初始化设置在compiler段,从而使得它在绝大多数全局变量和几乎所有的用户定义的全局变量之前初始化。

4.记录内存分配

一个分配钩子函数需要具有如下的形式:

intYourAllocHook(intallocType,void*userData, size_t size,intblockType,longrequestNumber,constunsignedchar*filename,intlineNumber);

就像前面说的,它在Visual Leak Detector初始化时被注册,每次从调试堆分配内存之前被调用。这个函数需要处理的事情是记录下此时的调用堆栈和此次堆内存分配的唯一标识——requestNumber。

得到当前的堆栈的二进制表示并不是一件很复杂的事情,但是因为不同体系结构、不同编译器、不同的函数调用约定所产生的堆栈内容略有不同,要解释堆栈并得到整个函数调用过程略显复杂。不过windows提供一个StackWalk64函数,可以获得堆栈的内容。StackWalk64的声明如下:

BOOLStackWalk64(
DWORDMachineType,
HANDLEhProcess,
HANDLEhThread,
LPSTACKFRAME64StackFrame,
PVOIDContextRecord,
PREAD_PROCESS_MEMORY_ROUTINE64ReadMemoryRoutine,
PFUNCTION_TABLE_ACCESS_ROUTINE64FunctionTableAccessRoutine,
PGET_MODULE_BASE_ROUTINE64GetModuleBaseRoutine,
PTRANSLATE_ADDRESS_ROUTINE64TranslateAddress
);

STACKFRAME64结构表示了堆栈中的一个frame。给出初始的STACKFRAME64,反复调用该函数,便可以得到内存分配点的调用堆栈了。

 // Walk the stack.
while(count < _VLD_maxtraceframes) {
count++;
if(!pStackWalk64(architecture, m_process, m_thread, &frame, &context,
NULL, pSymFunctionTableAccess64, pSymGetModuleBase64, NULL)) {
// Couldn't trace back through any more frames.
break;
}

转自:http://www.51testing.com/html/38/106738-82006.html

使用Visual Leak Detector检测内存泄漏[转]的更多相关文章

  1. vld&lpar;Visual Leak Detector&rpar; 内存泄露检测工具

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

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

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

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

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

  4. 转载:C&sol;C&plus;&plus;检测内存泄漏的工具 vld Visual Leak Detector223 的使用方法和sample示例

    这类的工具有 比如 :LeakDiag leakfinder "Visual Leak Detector" vld可以从http://vld.codeplex.com/releas ...

  5. Visual Leak Detector 2&period;2&period;3 Visual C&plus;&plus;内存检测工具

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

  6. 关于Visual Leak Detector的配置与使用 &lpar;测试vector 引起的内存泄漏问题&rpar;

    之前在做一个音频特征提取的批量处理程序,老是出现内存泄露问题,用Visual Leak Detector(VLD)工具做了下检测,检测出了一些问题,解决后还是会有问题.之后继续排查,因为我的代码中,大 ...

  7. 使用Visual Leak Detector for Visual C&plus;&plus; 捕捉内存泄露

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

  8. Identify Memory Leaks in Visual CPP Applications —— VLD内存泄漏检测工具

    原文地址:http://www.codeproject.com/Articles/1045847/Identify-Memory-Leaks-in-Visual-CPP-Applications 基于 ...

  9. VisualStudio 怎么使用Visual Leak Detector

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

随机推荐

  1. &lbrack;原&rsqb;CentOS7&period;2最小安装环境部署Asp&period;NET Core笔记

    转载请注明原作者(think8848)和出处(http://think8848.cnblogs.com) 写在前面的话 不知不觉在cnblogs上注册已经10多年了,看我的园龄就直接暴露了我实际年龄, ...

  2. paper 106:图像增强方面的介绍

    图像增强是从像素到像素的操作,是以预定的方式改变图像的灰度直方图.有时又称为对比度增强,灰度变换.点运算不可能改变图像内的空间关系,输出像素的灰度值由输入像素的值决定.其作用: 对比度增强:扩展感兴趣 ...

  3. SQL Server 2008 建立分区表 脚本

    /*第一步:创建分区函数*/Create partition function Part_func_Bag(varchar(20)) as range right /*正式区间for values(N ...

  4. Android 设置界面的圆角选项

    请先看一个图: 像这种界面的设计,其实是这样的:整体为一个LinearLayout,一个一个排下去,每一个点击项都是一个RelativeLayout(要为其设置clickable为true),分为左右 ...

  5. linux mysql 卸载后重装

    $sudo apt-get remove mysql-common清理残留数据:$sudo dpkg -l |grep ^rc|awk '{print $2}' |sudo xargs dpkg -P ...

  6. Laravel PHP Web开发框架

    Laravel是一套简洁.优雅的PHP Web开发框架(PHP Web Framework).它可以让你从面条一样杂乱的代码中解脱出来:它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁.富于 ...

  7. 【读书笔记】C&plus;&plus;Primer---第三章

    1.由于为了与C语言兼容,字符串字面值与标准库string类型不是同一种类型: 2.以下代码中,cin有几点需要注意:a.读取并忽略开头所有的空白字符(如空格.换行符.制表符):b.读取字符直至再次遇 ...

  8. windows下的node环境搭建

    node环境的搭建过程: 1.首先在nodejs.org官网上下载一个msi安装文件,安装(过程很简单,基本上是一路next) 2.安装完成后,简单测试下是否安装成功,在cmd下输入两个命令: nod ...

  9. Ubuntu18&period;04终端设置为zsh后的问题记录

    1. 在将终端从bash切换成zsh后,需要将 .bashrc 下的一些配置迁移到 .zshrc 中: 例如,笔者在使用zsh中使用virtualenv及virtualenvwrapper的相关命令时 ...

  10. 偏前端-vue&period;js学习之路初级(二)组件化构建

    vue.js   组件化构建 组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型.自包含和通常可复用的组件构建大型应用.仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树: ...