首页 > 其他分享 >QT Visual Leak Detector 输出解析(二)

QT Visual Leak Detector 输出解析(二)

时间:2024-03-04 18:33:40浏览次数:17  
标签:泄漏 exe QT Leak bytes CD Visual 内存

1. 使用方式
  在 QT 中使用 VLD 的方法可以查看另外几篇博客:

  • QT 使用 Visual Leak Detector(方式一)
  • QT 使用 Visual Leak Detector(方式二)
  • QT 使用 Visual Leak Detector(方式三)

  本次测试使用的环境为:QT 5.9.2,MSVC 2015 32bit,Debug 模式,VLD 版本为 2.5.1,VLD 配置文件不做任何更改使用默认配置,测试工程所在路径为:E:\Cworkspace\Qt 5.9\QtDemo\testVLD。

2. 有一处内存泄漏时的输出报告(int 型)
  写一个有一处内存泄漏的程序,如下:

 1 #include <QCoreApplication>
 2 #include "vld.h"
 3 
 4 void testFun()
 5 {
 6     int *ptr = new int(0x55345678);
 7     printf("ptr = %08x, *ptr = %08x", ptr, *ptr);
 8 }
 9 
10 int main(int argc, char *argv[])
11 {
12     QCoreApplication a(argc, argv);
13 
14     testFun();
15 
16     return a.exec();
17 }

  程序运行时,在标准输出窗会输出以下结果:

ptr = 0127b7a0, *ptr = 55345678

  程序运行结束后,检测到了内存泄漏,VLD 会输出以下报告(本例中出现一处内存泄漏),第 1~3 行显示 VLD 运行状态,第 4~21 行显示泄漏内存的详细信息,第 22~24 行总结此次泄漏情况,第 25 行显示 VLD 退出状态。

 1 Visual Leak Detector read settings from: D:\Program Files (x86)\Visual Leak Detector\vld.ini
 2 Visual Leak Detector Version 2.5.1 installed.
 3 WARNING: Visual Leak Detector detected memory leaks!
 4 ---------- Block 1 at 0x0127B7A0: 4 bytes ----------
 5   Leak Hash: 0xEB4D3A14, Count: 1, Total 4 bytes
 6   Call Stack (TID 22408):
 7     ucrtbased.dll!malloc()
 8     f:\dd\vctools\crt\vcstartup\src\heap\new_scalar.cpp (19): testVLD.exe!operator new() + 0x9 bytes
 9     e:\cworkspace\qt 5.9\qtdemo\testvld\main.cpp (6): testVLD.exe!testFun() + 0x7 bytes
10     e:\cworkspace\qt 5.9\qtdemo\testvld\main.cpp (16): testVLD.exe!main()
11     f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl (74): testVLD.exe!invoke_main() + 0x1B bytes
12     f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl (264): testVLD.exe!__scrt_common_main_seh() + 0x5 bytes
13     f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl (309): testVLD.exe!__scrt_common_main()
14     f:\dd\vctools\crt\vcstartup\src\startup\exe_main.cpp (17): testVLD.exe!mainCRTStartup()
15     KERNEL32.DLL!BaseThreadInitThunk() + 0x19 bytes
16     ntdll.dll!RtlGetAppContainerNamedObjectPath() + 0x11E bytes
17     ntdll.dll!RtlGetAppContainerNamedObjectPath() + 0xEE bytes
18   Data:
19     78 56 34 55                                                  xV4U.... ........
20 
21 
22 Visual Leak Detector detected 1 memory leak (40 bytes).
23 Largest number used: 40 bytes.
24 Total allocations: 40 bytes.
25 Visual Leak Detector is now exiting.

  第 1 行表示 VLD 读取的配置文件路径,可以根据路径找到该文件,然后更改里面的相关配置,获得想要的效果。

  第 2 行表示 VLD 2.5.1 在程序中初始化成功。

  第 3 行表示本次运行检测到了内存泄漏。

  第 4 行中,Block 1 表示本块内存是在堆上分配的第 1 个内存块,0x0127B7A0 表示该内存块的首地址,与标准输出窗输出的 ptr = 0127b7a0 一致,4 bytes 表示该内存块的大小,这一行输出了泄漏内存块的地址信息和大小信息。

  第 5 行中,Leak Hash: 0xEB4D3A14 是由泄漏块大小及调用堆栈信息计算出的唯一标识符,如果在报告中看到相同的 Leak Hash,这表示这些泄漏块具有相同大小和相同的调用堆栈。Count: 1 是发生泄漏的计数,使用默认配置时全部等于 1,可以将配置文件中的参数 AggregateDuplicates 设置为 yes 来合并显示具有相同 Leak Hash 值的的泄漏块信息。Total 4 bytes 是此内存块的泄漏大小,与第 4 行一致。这一行输出了泄漏内存块的唯一标识符、泄漏频次、大小信息。

  第 6 行中,Call Stack 表示接下来的几行是产生泄漏的调用堆栈,(TID 22408) 表示产生此内存泄漏块函数所在线程的 TID 为 22408,据此来指示发生内存泄漏的线程。在调试多线程程序时,TID 信息很有帮助,它能帮助确定泄漏所在线程。

  第 7 行中,ucrtbased.dll 是一个系统库,提供了各种标准 C 和 C++ 函数的实现,包括 malloc(),这个函数用于在运行时动态分配内存。它处于调用栈顶,表示此内存块是使用 ucrtbased.dll 库中的 malloc() 分配的,然后传递给第 8 行 testVLD.exe 程序中的 operator new()。

  第 8 行中,f:\dd\vctools\crt\vcstartup\src\heap\new_scalar.cpp 是从 MSVC 中获取的调试信息,这个路径是内置在 Visual C++ Runtime Library 中的,并不代表 new_scalar.cpp 的真实路径,它的真实路径一般在 Visual Studio 的安装目录下。在我电脑上:

  Visual Studio 2015 使用的 new_scalar.cpp 文件真实路径为 C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\crt\src\vcruntime\new_scalar.cpp;
  Visual Studio 2019 使用的 new_scalar.cpp 文件真实路径为 D:\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\crt\src\vcruntime\new_scalar.cpp。
  在不同系统上的相同版本的 Visual C++ Runtime Library 中,这个内置路径通常是一样的。(19) 表示 operator new() 函数中分配内存的代码位于 new_scalar.cpp 文件的第 19 行,最后面的 + 0x9   bytes 表示从 operator new() 函数开始到导致泄漏产生的指令的内存偏移量,这些信息在调试时很有用,可以帮助快速定位到确切代码行。

  第 9 行中,e:\cworkspace\qt 5.9\qtdemo\testvld\main.cpp (6): testVLD.exe!testFun() + 0x7 bytes 表示 main.cpp 位于 e:\cworkspace\qt 5.9\qtdemo\testvld 路径下,这与项目实际路径是一致的,差别只是 VLD 将其全部转成了小写字母形式,testFun() 函数中分配内存的代码位于 main.cpp 的第 6 行,这与实际情况完全一致。最后面的 + 0x7 bytes 表示从 testFun() 函数开始到导致泄漏产生的指令的内存偏移量,这个信息据说是多用于汇编调试中,与实际是否能对上还没仔细研究过。

  第 10 行中,e:\cworkspace\qt 5.9\qtdemo\testvld\main.cpp (16): testVLD.exe!main() 表示 main() 函数中分配内存的代码位于 main.cpp 的第 16 行,没有提供指令的内存偏移信息,这与实际情况(第 14 行)有些差异,不过第 14 与第 16 行之间并没有别的代码,造成这种差异的原因有待深究,但对于定位泄漏点所在位置已经够用了。

  第 11~14 行,跟踪显示了启动程序所调用的函数链,其中 mainCRTStartup() 函数是入口点。

  第 15~17 行,跟踪显示了程序启动时所调用的 Windows 操作系统函数,BaseThreadInitThunk() 一般都会出现在调用栈底,它是 Windows 进程中所有用户模式线程的入口点,系统调用它在进程中启动一个新线程,并由它调用程序的主函数。ntdll.dll 中的 RtlGetAppContainerNamedObjectPath() 函数被调用了两次,但指令的内存偏移量不同(分别是 0x11E bytes 和 0xEE bytes),这也是一个 Windows 操作系统函数,用于检索与进程相关的应用程序容器名称,由 Windows 系统的各个部分和其他需要知道应用程序容器名称的程序调用,关于 Windows 容器的介绍,可以查看 Microsoft Windows 和容器。

  第 18~19 行,分别用十六进制及 ASCII 字符显示了泄漏内存块中信息,内存初始化时赋的初始值为 0x55345678,计算机默认使用小端字节序,因此在内存中各字节的十六进制初始值分别为 78 56 34 55,转化为十进制数,0x78、0x56、0x34、0x55 分别为 120、86、52、85,查找 ASCII 码表,可得这四个字节对应的 ASCII 字符分别为 x、V、4、U,与 VLD 的输出完全一致。VLD 在显示内存内容时,每行最多显示 16 个字节,但这次只泄漏了 4 个字节,因此在显示上第 19 行中间有 12 个字节的空白位,行尾有 12 个占位点(.... ........)。

  第 22 行,表示本次运行检测到 1 处内存泄漏,泄漏的总大小为 40 bytes,这里面不光包含用于 int 存储的 4 bytes,还包含用于管理追踪这块内存的另外 36 bytes,因此,虽然代码只请求了 4 bytes 的内存,但程序实际上为此分配了 40 bytes 的内存。(实际测试发现,使用 32 bit 的编译器时,这个管理头的大小为 36bytes,当使用 64 bit 的编译器时,大小变为 52bytes。)

  第 23 行,表示本次运行中单次分配的最大内存大小,为 40 bytes,原因看前一条。在实际使用过程中,这个 Largest number used 有时候跟实际情况对不上,又好像表示本次运行中分配的连续堆内存最大宽度,有兴趣的可以深入研究。

  第 24 行,表示本次运行中堆上分配内存的总大小,为 40 bytes,即代码申请 int 的 4 bytes,和管理头占用的 36 bytes。

  第 25 行,表示 VLD 正常退出。

  在程序的第 6 行加个断点,按 F5 进入调试状态,结果如下,调用堆栈中各函数的名称、所属文件、所在行号、调用顺序都和 VLD 一致。

3. 有一处内存泄漏时的输出报告(int 数组型)

  写一个有一处内存泄漏的程序,如下:

 1 #include <QCoreApplication>
 2 #include "vld.h"
 3 
 4 void testFun()
 5 {
 6     int *ptr = new int[10];
 7     ptr[0] = 0x64568932;
 8     printf("ptr = %08x", ptr);
 9 }
10 
11 int main(int argc, char *argv[])
12 {
13     QCoreApplication a(argc, argv);
14 
15     testFun();
16 
17     return a.exec();
18 }

  程序运行时,在标准输出窗会输出以下结果:

ptr = 00ab4340

  程序运行结束后,检测到了内存泄漏,VLD 会输出以下报告(本例中出现一处内存泄漏),第 1~3 行显示 VLD 运行状态,第 4~23 行显示泄漏内存的详细信息,第 24~26 行总结此次泄漏情况,第 27 行显示 VLD 退出状态。

 1 Visual Leak Detector read settings from: D:\Program Files (x86)\Visual Leak Detector\vld.ini
 2 Visual Leak Detector Version 2.5.1 installed.
 3 WARNING: Visual Leak Detector detected memory leaks!
 4 ---------- Block 1 at 0x00AB4340: 40 bytes ----------
 5   Leak Hash: 0x39CB72AB, Count: 1, Total 40 bytes
 6   Call Stack (TID 29256):
 7     ucrtbased.dll!malloc()
 8     f:\dd\vctools\crt\vcstartup\src\heap\new_array.cpp (15): testVLD.exe!operator new[]() + 0x9 bytes
 9     e:\cworkspace\qt 5.9\qtdemo\testvld\main.cpp (6): testVLD.exe!testFun() + 0x7 bytes
10     e:\cworkspace\qt 5.9\qtdemo\testvld\main.cpp (17): testVLD.exe!main()
11     f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl (74): testVLD.exe!invoke_main() + 0x1B bytes
12     f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl (264): testVLD.exe!__scrt_common_main_seh() + 0x5 bytes
13     f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl (309): testVLD.exe!__scrt_common_main()
14     f:\dd\vctools\crt\vcstartup\src\startup\exe_main.cpp (17): testVLD.exe!mainCRTStartup()
15     KERNEL32.DLL!BaseThreadInitThunk() + 0x19 bytes
16     ntdll.dll!RtlGetAppContainerNamedObjectPath() + 0x11E bytes
17     ntdll.dll!RtlGetAppContainerNamedObjectPath() + 0xEE bytes
18   Data:
19     32 89 56 64    CD CD CD CD    CD CD CD CD    CD CD CD CD     2.Vd.... ........
20     CD CD CD CD    CD CD CD CD    CD CD CD CD    CD CD CD CD     ........ ........
21     CD CD CD CD    CD CD CD CD                                   ........ ........
22 
23 
24 Visual Leak Detector detected 1 memory leak (76 bytes).
25 Largest number used: 76 bytes.
26 Total allocations: 76 bytes.
27 Visual Leak Detector is now exiting.

  输出与 [2. 有一处内存泄漏时的输出报告(int 型)](#2. 有一处内存泄漏时的输出报告(int 型)) 基本类似,这里提几个不同点:

  第 4~5 行中,40 bytes 与代码请求的内存量大小相同,即 sizeof(int) * 10 = 40。

  第 8 行,表示 operator new[]() 函数中分配内存的代码位于 new_array.cpp 文件的第 15 行,这与前面的 operator new() 函数及 new_scalar.cpp 文件不同,实际使用时可以根据这一点来判断泄漏形式,是数组还是标量。

  第 19~21 行,十六进制数 32 89 56 64 的十进制表示为 50 137 86 100,其中 50 86 100 对应的 ASCII 字符分别为 2、 V、 d,是可以输出显示的字符,但 137 超过了 127,不属于 ASCII 标准字符集,属于 ASCII 扩展字符集,无法直接在界面上显示,因此仍以 "." 英文句点来代替。此外,未初始化内存单个字节的值都为 CD,对应的十进制数为 205,这是 Microsoft's C++ debugging runtime library 自动初始化的结果。通常,在 Debug 模式下,MSVC 会把未初始化的栈内存全部填充成 0xCC ,当成字符串看就是”烫烫烫烫……“;同时会把未初始化的堆内存全部填充成 0xCD ,当成字符串看就是“屯屯屯屯……”。实际使用时可以根据这一点来判断是否对泄漏内存赋了初始值。
  第 24~26 行中,76 bytes 包含有申请 int[10] 的 40 bytes,和管理头占用的 36 bytes

标签:泄漏,exe,QT,Leak,bytes,CD,Visual,内存
From: https://www.cnblogs.com/ybqjymy/p/18052392

相关文章

  • Qt 使用 Visual Leak Detector(方式二)
    1.使用前的准备参考本人另一篇博客安装VisualLeakDetector下载vld-2.5.1-setup.exe并按步骤安装VLD。这一种使用方式的特点是,在一台电脑上安装完成后,需在项目pro文件中指明库及头文件的路径,然后在mian.cpp文件中#include"vld.h"。当把项目拷贝到别的电脑上编译......
  • Qt 使用Visual Leak Detector(方式三)
    1.使用前的准备参考本人另一篇博客安装VisualLeakDetector下载vld-2.5.1-setup.exe并按步骤安装VLD。这一种使用方式的特点是,在一台电脑上安装完成后,将VLD安装目录下的lib库及include文件拷贝到项目目录中,在项目pro文件中指明库及头文件的路径,并将vld.ini......
  • Qt 使用 Visual Leak Detector(方式一)
    1.使用前的准备参考本人另一篇博客安装VisualLeakDetector下载vld-2.5.1-setup.exe并按步骤安装VLD。这一种使用方式的缺点是,当把项目拷贝到别的电脑上编译运行时,需要按以下流程重新配置VLD环境。但优点是在一台电脑上配置完成后,用的时候十分方便,包含头文件就可以......
  • Qt MSVC使用内存泄露检测工具 VLD(Visual Leak Detector)
    一、简介VLD=VisualLeakDetector,是一款用于VisualC++的免费的内存泄露检测工具,官网 kinddragon.github.io, GitHub 。先说优点:为每个泄漏的块提供完整的堆栈跟踪,包括源文件和行号信息(如果可用)。检测大多数(如果不是全部)类型的进程内内存泄漏,包括基于COM的泄漏......
  • Visual Leak Detector 安装 VLD
    一.工具下载VisualLeakDetector官网下载地址:https://kinddragon.github.io/vld/,点击DownloadInstaller绿色按钮可下载工具的安装程序vld-2.5.1-setup.exe。也可去Git仓库releases界面下载安装程序vld-2.5.1-setup.exe。二.工具安装2.1Next2.2Iacceptt......
  • Visual Studio 性能探查器排查内存泄漏
    1、自用方法介绍【1】VS使用debug模式执行程序(注意:Release模式无法看到堆栈细节!)【2】截取内存快照2、别人方法介绍【1】首先用vsattach到进程,再点调试–窗口–显示诊断工具。注意:如果用调试–性能探测器去附加进程,则内存使用率这一项是灰的,无法勾选,但是......
  • Visual Studio 打开Qt项目
    一、下载QTVSTOOL插件1.1下载地址官方下载地址:Indexof/development_releases/vsaddin找到对应的VS版本下载1.2 安装先关闭VS,然后安装,在打开VS,就看到顶部有QTVSTOOLS 了1.3 添加路径QtOptions->Add->apth,找到你Qt安装的目录对应的如下文件夹Q......
  • Visual Leak Detector 简介
    1.工具简介VisualLeakDetector简称VLD,是Windows平台下用于C/C++代码内存泄漏检测的开源工具,使用起来比较简单,配置好环境后包含头文件,就可以在运行时自动检测是否存在内存泄漏,并在指定位置(控制台或者文本文件)输出检测报告。该工具最初由DanMoulding开发,但是后面2.......
  • 调整window下qt界面的缩放比例为自适应
    原因:QtCreator的缩放策略是四舍五入,只能缩放到1或2,而不是1.5,就比如系统缩放为150%,qt界面则会被缩放为200%解决办法:Linux下:exportQT_SCALE_FACTOR_ROUNDING_POLICY=PassThrough1.这行代码是环境变量设置的一部分,用于指定QT应用程序的缩放因子舍入策略。QT_SCALE_FACTOR......
  • JVisualVM连接远程服务器
    要使用JVisualVM连接远程服务器,你需要在远程服务器上配置JVM以允许JVisualVM进行远程连接,然后在本地JVisualVM中添加远程主机。以下是连接远程服务器的步骤:远程服务器配置配置JVM启动参数:在启动Java应用程序时,需要添加一些JVM参数来启用远程监控。例如,使用以下参数启动应用程......