Qt / MSVC 中使用内存泄露检测工具 VLD(Visual Leak Detector)

1 篇文章 0 订阅

 

一、简介

VLD = Visual Leak Detector,是一款用于 Visual C++ 的免费的内存泄露检测工具,官网 kinddragon.github.io, GitHub 。先说优点:

  • 为每个泄漏的块提供完整的堆栈跟踪,包括源文件和行号信息(如果可用)。
  • 检测大多数(如果不是全部)类型的进程内内存泄漏,包括基于 COM 的泄漏和纯 Win32 基于堆的泄漏。
  • 可以设置过滤指定的模块(DLL 甚至主 EXE),不参与内存泄露检查。
  • 提供泄漏块的完整数据转储(十六进制和 ASCII)。
  • 可自定义的内存泄漏报告:可以保存到文件或发送到调试器,并且可以包含可变的详细级别
  • 可以设置内存泄露报告的级别
  • 它是一个已经打包的 lib,使用时无须编译它的源代码,只需要引入头文件即可
  • 他的源代码使用 GNU 许可发布,并有详尽的文档及注释。对于想深入了解堆内存管理的读者,是一个不错的选择。

再谈缺点,或者说限制性:

1、只针对 Visual C++ ,所以 Qt 的项目如果是 MinGW 编译的需要调整为 MSVCXX 构建。

2、只能检测堆(Heap)上分配的内存泄漏,不能检测资源泄露(如 GDI 等系统资源)。

总的来说,对于在 Windows 环境下用 VC++ 编译的项目,是免费且十分容易使用的非常棒的内存泄露检查库。可惜目前停留在了 2.5.1 版 (2017-10-17)。

二、下载安装 

Releases · KindDragon/vld (github.com) ,基于众所周知的原因,下不到的请移步于此:(VisualLeakDetector)vld-2.5.1-setup.exe.7z

下载解压后安装一路点击就可以了。

三、在 Qt 中使用

使用 VLD 很简单,对于 Qt 项目只需要以下三步即可(假设我们都安装在 D:\VLD 目录下):

  • 复制头文件、lib文件

      将 D:\VLD\下的 include 子目录下的 .h 文件都复制到 Qt 项目对应的构建库目录下对应的 include 、 lib 子目录中。

构建目录可以通过菜单 工具/选项,Kits中找到项目对应的构建套件(KIT),并找到对应的 qmake.exe所在路径,其父路径就是我们要找的构建库目录,如我这里是 E:\Qt\Qt5.12.2\5.12.2\msvc2017。

  • 源码中引入 vld

        包含 vld.h 头文件即可。

  • 修改 .pro 项目文件(这一步,我测试不需要,也许是版本问题?) 
  • win32 {
               CONFIG(debug, debug|release) {
               #        DEFINES += _DEBUG
               VLD_PATH = C:/Program Files (x86)/Visual Leak Detector
               INCLUDEPATH += $VLD_PATH/include
               LIBS += -L$VLD_PATH/lib/Win32 -lvld
                }
           }

如果希望检查 DLL 的内存泄漏,则还要在每个 DLL 的至少一个源文件中包括 vld.h。

经过如上配置,跑起程序来,如果配置正确,则在【应用程序输出】窗口中,可以看到vld的输出,如下

18:14:33: Debugging starts

Visual Leak Detector read settings from: D:\VLD\vld.ini

Visual Leak Detector Version 2.5.1 installed.

退出程序,则在【应用程序输出】窗口中看到输出,如下

 No memory leaks detected.

Visual Leak Detector is now exiting.

18:14:40: Debugging has finished

很好,没有泄露,让我们刻意制造一个泄露:

    int * p = new int();
    *p = 0xAABBFF;

    qDebug() << "p address : " << p;

new 一个 int 型指针,赋值为 0xAABBFF,最后显示指针地址。测试下 VLD 是否能捕获到这个泄露,进一步,是否能显示泄露内存的数据。

跑起来程序后关闭窗口退出, VLD 显示如下,对关键数据用红色粗斜体标注,并配了#序号: 

#1 p address :  0x40b95a8
WARNING: Visual Leak Detector detected memory leaks!
#2 ---------- Block 8 at 0x040B95A8: 4 bytes ----------
#3   Leak Hash: 0xF4DB2A55, Count: 1, Total 4 bytes
  Call Stack (TID 11204):
    ucrtbased.dll!malloc()
    d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\heap\new_scalar.cpp (35): testvld.exe!operator new() + 0x9 bytes
    e:\test\qt\vld\testvld\mainwindow.cpp (19): testvld.exe!MainWindow::MainWindow() + 0x10 bytes
 #4  e:\test\qt\vld\testvld\main.cpp (7): testvld.exe!main() + 0xA bytes
    c:\users\qt\work\qt\qtbase\src\winmain\qtmain_win.cpp (97): testvld.exe!WinMain() + 0xD bytes
    d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl (107): testvld.exe!invoke_main()
    d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl (288): testvld.exe!__scrt_common_main_seh() + 0x5 bytes
    d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl (331): testvld.exe!__scrt_common_main()
    d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\startup\exe_winmain.cpp (17): testvld.exe!WinMainCRTStartup()
    KERNEL32.DLL!BaseThreadInitThunk() + 0x19 bytes
    ntdll.dll!RtlGetAppContainerNamedObjectPath() + 0x11E bytes
    ntdll.dll!RtlGetAppContainerNamedObjectPath() + 0xEE bytes
 #5 Data:
    FF BB AA 00    
                       
   
                 ........ ........


Visual Leak Detector detected 1 memory leak (40 bytes).
Largest number used: 498 bytes.
Total allocations: 498 bytes.
Visual Leak Detector is now exiting.
10:21:38: Debugging has finished

#1 是我们程序中输出的地址0x40b95a8 和 VLD 检测到的(#2 Block 8 at 0x040B95A8: 4 bytes)地址一致,并且指出了数据长度为 4 字节。

#4 给出了产生泄露代码文件地址及(e:\test\qt\vld\testvld\main.cpp)、行号(7)及所在函数(testvld.exe!main())

#5 显示出泄露的内存数据片段,正是我们赋值的 0xAABBFF,只是大小端问题,显示为 FF BB AA 00 。

可见,VLD可以非常明确的捕获内存泄露并指出相关的具体信息。

上面是使用 Debug 版输出的情况,接下来看

Release版本如何使用?

在工程设置里加上 VLD_FORCE_ENABLE 预定义宏内存监控才会生效。

#define VLD_FORCE_ENABLE
#include "vld/vld.h"

相比 Debug 版,Release 版的信息少了很多

p address : 0xba1fa0

WARNING: Visual Leak Detector detected memory leaks!

---------- Block 8 at 0x00BA1FA0: 4 bytes ----------

Leak Hash: 0x25F7E302, Count: 1, Total 4 bytes

Call Stack (TID 544):

ucrtbase.dll!malloc()

testvld.exe!0x0098185C()

testvld.exe!0x00981107()

testvld.exe!0x0098105C()

testvld.exe!0x009826D5()

Data:

FF BB AA 00 ........ ........

Visual Leak Detector detected 1 memory leak (4 bytes).

Largest number used: 214 bytes.

Total allocations: 214 bytes.

Visual Leak Detector is now exiting.

10:57:20: Debugging has finished

对比两份输出,缺少的部分是函数调用堆栈,也就是说在 release 版中无法获取内存泄露代码的文件路径、行号、调用函数信息。

但因为提供了内存地址、内存数据片段及大小,对问题的排查帮助还是很大的。

四、在 MSVC++ 中使用

和 Qt 环境的主要区别就是路径的配置方式不同,以 VS2017为例,在项目右键属性中配置如下

配置头文件查找目录

 

 配置 lib 目录

配置好后,还需要在 VLD 安装目录下 bin 下对应的平台调试文件复制到程序所在目录,如

 如上配置后,源码中也是同样的 #include "vld.h",之后编译运行即可。

五、配置内存泄露报告

VLD 的内存泄露报告是可以定制的,详细的配置描述请参考 Configuration Options · KindDragon/vld Wiki · GitHub

安装目录下的vld.ini 为默认全局配置,也可以为每个程序单独配置,在应用程序目录下放置vld.ini文件即可。常用的选项如下:
 

VLD:选择VLD的打开与关闭。在Debug模式下运行,关闭以后会有一行VLD关闭的提示信息。默认为 on。

AggregateDuplicates:设置为 yes 时,相同地方产生内存泄漏只输出一次,但是会统计发生的次数。默认是 no 。

ReportEncoding :report 文件的编码格式,可选有 ascii, unicode,默认是 ascii 。

ReportFile :report 文件的路径。默认是 “.\memory_leak_report.txt”

ReportTo :可选有 debugger, file, both,debugger 表示输出到 debug模式下的输出窗口;file 表示只输出到文件中; both顾名思义,全都都输出。默认是 debugger 。

* 如果需要将报告输出到指定文件中,则配置 ReportFile = .\报告文件名 且 ReportTo = both。
 

参考 

Home · KindDragon/vld Wiki · GitHub 

Qt Creator 安装 VLD_你好L的博客-CSDN博客_qt vld

QT 内存泄漏检测工具VLD 使用和安装_小何在线的博客-CSDN博客_qt vld

Configuration Options · KindDragon/vld Wiki · GitHub

  • 5
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Visual Leak Detector是一款用于Visual C++的免费的内存泄露检测工具。相比较其它的内存泄露检测工具,它在检测到内存泄漏的同时,还具有如下特点: 1、 可以得到内存泄漏点的调用堆栈,如果可以的话,还可以得到其所在文件及行号; 2、 可以得到泄露内存的完整数据; 3、 可以设置内存泄露报告的级别; 4、 它是一个已经打包的lib,使用时无须编译它的源代码。而对于使用者自己的代码,也只需要做很小的改动; 5、 他的源代码使用GNU许可发布,并有详尽的文档及注释。对于想深入了解堆内存管理的读者,是一个不错的选择。 可见,从使用角度来讲,Visual Leak Detector简单易用,对于使用者自己的代码,唯一的修改是#include Visual Leak Detector的头文件后正常运行自己的程序,就可以发现内存问题。从研究的角度来讲,如果深入Visual Leak Detector源代码,可以学习到堆内存分配与释放的原理、内存泄漏检测的原理及内存操作的常用技巧等。 下面让我们来介绍如何使用这个小巧的工具。 首先解压得到vld.h, vldapi.h, vld.lib, vldmt.lib, vldmtdl l.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
目前有一款常用的内存泄漏检测工具Visual Leak Detector(VLD)。 VLD是一款免费的内存泄漏检测工具,适用于Visual C环境。它能够为每个泄漏的块提供完整的堆栈跟踪信息,包括源文件和行号。同时,VLD可以检测大多数类型的进程内内存泄漏,包括基于COM的泄漏和纯Win32基于堆的泄漏。此外,VLD还支持设置过滤指定的模块,不参与内存泄漏检查,并提供泄漏块的完整数据转储。你可以将泄漏报告保存到文件或发送到调试器,并可以设置不同的详细级别。VLD是一个已经打包的库,使用时无需编译其源代码,只需引入头文件即可。它的源代码使用GNU许可发布,并有详尽的文档和注释,适合想深入了解堆内存管理的读者使用。 [2] 另外,还有一种内存泄漏检测工具QT内置的功能。当一个QObject正在接受事件队列时,如果途被销毁,可能会导致问题。为了避免这种情况,推荐使用QObject的deleteLater()函数来删除QObject对象。这个函数会发送一个删除事件到事件系统,让所有事件都处理完之后再清除内存。而且,即使多次调用deleteLater()函数也不会出现问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Qt / MSVC 使用内存泄露检测工具 VLD(Visual Leak Detector)](https://blog.csdn.net/weixin_41863029/article/details/128482295)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Qt内存泄漏总结(包括检测工具)](https://blog.csdn.net/a844651990/article/details/78814076)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0x0007

可不可奖励我吃只毛嘴鸡 馋😋

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值