近期想学习下VLD的实现,打算从最简单的V1.0版本看起。以下是V1.0版本自己尝试翻译下,最新的2.x版本似乎强大了很多。
简介
Visual C++提供了内置的内存检测机制,但其充其量只满足了最小定位需求。VLD工具定位为内置内存泄漏的替代,提供了如下特性:
- 泄漏内存块的全调用栈回溯,包括文件及其行号;
- 泄漏内存完整转储(hex和ascii格式);
- 可定制的泄漏报告等级(报告的详细程度可配置)
- 简单易用。不需要去编译源代码,仅需要在工程中添加几行代码即可完成集成;
- 提供泄漏内存调用栈和内存转储;
- 兼容C\C++(对new/delete和malloc/free都有效)
- 全代码开源并有良好的帮助文档,易用按需修改以进行工程适配;
使用VLD
如果你需要同时检查工程包含的DLL,见"在DLL中检测",步骤:
- 拷贝VLD库文件(*.lib)到工程的lib目录下;
- 拷贝VLD头文件(vld.h和vldapi.h)到include目录下;
- 在程序主入口的源文件中,包含vld.h文件。这样做最好,但不是绝对的,包含语句应在其他包含语句之前但在stdafx.h包含语句之后(紧接#include "stdafx.h"之后);
- 如果程序在Windows2000或之前的系统运行,需要拷贝dbghelp.dll到执行文件所在目录;
- 编译debug版本的工程;
VLD会自动在debug版本的程序中进行内存泄漏检测,并在程序退出时自动在输出窗口打印出泄漏报告。注意:当编译的为Release版本的程序,VLD不会被链接到程序中。所以将vld.h的文件包含语句留在工程源代码中是安全的。
配置选项
VLD有一些预编译宏可以控制VLD的某些行为:
VLD_AGGREGATE_DUPLICATES 去除重复的内存泄漏信息。
VLD_MAX_TRACE_FRAMES 最大栈回溯深度;
VLD_MAX_DATA_DUMP 最大内存转储大小;
VLD_SELF_TEST 自我诊断,该特性总是激活的,每次运行VLD,VLD自身会故意泄漏21字节的内存,并填充字符串"Memory Leak Self-Test"。该特性用于确定VLD是否正在工作。
VLD_SHOW_USELESS_FRAMES 仅显示有用的栈信息,heap和vld自身的栈默认不显示;
VLD_START_DISABLED 禁止自使能,即手动启动VLD检测,这样可能导致一些检测失效。
VLD运行时
void VLDDisable(void); 禁用VLD;
void VLDEnable(void); 启用VLD;
在DLL中检测内存泄漏
检测DLL中的内存泄漏有些特殊注意事项以保证VLD正常运行:VLD在每个进程应只被一个模块链接;最佳建议是第一个被初始化的模块;详细情况如下:
隐式加载的DLL
隐式加载的DLL在应用程序main函数前就已经完成初始化。因此dll是第一个被初始化的模块,而VLD应该被其链接。一般情况下exe程序会链接多个DLL,只要在第一个需要被检查的模块里链接VLD即可。多个DLL的加载顺序可以通过在调试器里观察得出。
显式加载的DLL
显示加载(LoadLibrary)的DLL初始化在exe程序初始化之后,此时,exe程序应该作为链接VLD的模块;
静态链接CRT的DLL
当DLL使用/ML或者/MT编译器选项,会造成在一个进程中存在多个CRT实例。VLD的泄漏检测不能跨越CRT边界。一个VLD实例只能监视一个CRT实例的内存情况。如果要同时监视多个CRT实例,必须在每一个静态链接CRT的模块中都链接VLD;
已知的限制
VLD 不支持COM或其他和CRT堆无关的内存泄漏检测。简单的说:vld1.0版本只支持通过new或malloc开辟的内存的泄漏检测;
VLD不支持V6.5版本的dbghelp.dll;
已编译的VLD发行包和VS2005不兼容,如果需要支持请在VS2005下自行编译;