Visual Leak DetectorRelease 模式下使用 VLD

Posted 木三百川

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Visual Leak DetectorRelease 模式下使用 VLD相关的知识,希望对你有一定的参考价值。

使用 VLD 内存泄漏检测工具辅助开发时整理的学习笔记。本篇介绍如何在 Release 模式下使用 VLD。

说明

使用 VLD 内存泄漏检测工具辅助开发时整理的学习笔记。本篇介绍如何在 Release 模式下使用 VLD。同系列文章目录可见 《内存泄漏检测工具》目录


1. 思路概述

要在 RELEASE 模式下使用 VLD,必须在包含头文件 vld.h 前预先定义 VLD_FORCE_ENABLE 宏(参考 VLD Issues 46):

#define VLD_FORCE_ENABLE
#include "vld.h"

DEBUG 模式一样,可以在代码中使用 VLDGlobalEnableVLDReportLeaksVLDGlobalDisable 等 VLD 库提供的 API,也可以通过提前更改 vld.ini 配置文件,实现对 VLD 功能的定制。API 使用方法可查看 vld.h 头文件或本人同系列文章。

2. 在 QT 中实践

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

#include <QCoreApplication>

#define VLD_FORCE_ENABLE
#include "vld.h"

void testFun(int i)

    int *ptr = new int(i);
    printf("ptr = %08x, *ptr = %08x.\\n", ptr, *ptr);


int main(int argc, char *argv[])

    QCoreApplication a(argc, argv);

    testFun(1);

    return a.exec();

运行结束后,标准输出窗中输出以下结果:

ptr = 00e48270, *ptr = 00000001.

程序运行结束后,输出以下报告:

Visual Leak Detector read settings from: D:\\Program Files (x86)\\Visual Leak Detector\\vld.ini
Visual Leak Detector Version 2.5.1 installed.
WARNING: Visual Leak Detector detected memory leaks!
---------- Block 1 at 0x00E48270: 4 bytes ----------
  Leak Hash: 0xBE4F898C, Count: 1, Total 4 bytes
  Call Stack (TID 37180):
    ucrtbase.dll!malloc()
    testVLD.exe!0x00A510FA()
    testVLD.exe!0x00A51059()
    testVLD.exe!0x00A512C6()
    KERNEL32.DLL!BaseThreadInitThunk() + 0x19 bytes
    ntdll.dll!RtlGetAppContainerNamedObjectPath() + 0x11E bytes
    ntdll.dll!RtlGetAppContainerNamedObjectPath() + 0xEE bytes
  Data:
    01 00 00 00                                                  ........ ........


Visual Leak Detector detected 1 memory leak (4 bytes).
Largest number used: 4 bytes.
Total allocations: 4 bytes.
Visual Leak Detector is now exiting.

为了与 DEBUG 模式下的输出做比较,切换为 DEBUG 模式后的输出报告如下:

Visual Leak Detector read settings from: D:\\Program Files (x86)\\Visual Leak Detector\\vld.ini
Visual Leak Detector Version 2.5.1 installed.
WARNING: Visual Leak Detector detected memory leaks!
---------- Block 1 at 0x01123E48: 4 bytes ----------
  Leak Hash: 0x57574D54, Count: 1, Total 4 bytes
  Call Stack (TID 28696):
    ucrtbased.dll!malloc()
    f:\\dd\\vctools\\crt\\vcstartup\\src\\heap\\new_scalar.cpp (19): testVLD.exe!operator new() + 0x9 bytes
    e:\\cworkspace\\qt 5.9\\qtdemo\\testvld\\main.cpp (8): testVLD.exe!testFun() + 0x7 bytes
    e:\\cworkspace\\qt 5.9\\qtdemo\\testvld\\main.cpp (16): testVLD.exe!main() + 0x7 bytes
    f:\\dd\\vctools\\crt\\vcstartup\\src\\startup\\exe_common.inl (74): testVLD.exe!invoke_main() + 0x1B bytes
    f:\\dd\\vctools\\crt\\vcstartup\\src\\startup\\exe_common.inl (264): testVLD.exe!__scrt_common_main_seh() + 0x5 bytes
    f:\\dd\\vctools\\crt\\vcstartup\\src\\startup\\exe_common.inl (309): testVLD.exe!__scrt_common_main()
    f:\\dd\\vctools\\crt\\vcstartup\\src\\startup\\exe_main.cpp (17): testVLD.exe!mainCRTStartup()
    KERNEL32.DLL!BaseThreadInitThunk() + 0x19 bytes
    ntdll.dll!RtlGetAppContainerNamedObjectPath() + 0x11E bytes
    ntdll.dll!RtlGetAppContainerNamedObjectPath() + 0xEE bytes
  Data:
    01 00 00 00                                                  ........ ........


Visual Leak Detector detected 1 memory leak (40 bytes).
Largest number used: 40 bytes.
Total allocations: 40 bytes.
Visual Leak Detector is now exiting.

比较可知,RELEASE 模式下的报告,调用堆栈信息不够详细,且泄漏总内存中没有用于内存管理头的额外 36 bytes

Visual Leak Detector配置项 ReportEncoding

使用 VLD 内存泄漏检测工具辅助开发时整理的学习笔记。本篇介绍 VLD 配置文件中配置项 ReportEncoding 的使用方法。

说明

使用 VLD 内存泄漏检测工具辅助开发时整理的学习笔记。本篇介绍 VLD 配置文件中配置项 ReportEncoding 的使用方法。 同系列文章目录可见 《内存泄漏检测工具》目录


1. 配置文件使用说明

在程序中通过 #include "vld.h" 的方式检测内存泄漏时,VLD 首先会尝试在程序的生成目录下读取 vld.ini 文件,若未读取成功,则会尝试在 VLD 的安装目录下读取 vld.ini 文件,若仍未读取成功,则会使用内置的默认配置,内置的默认配置如果不动源码是无法更改的,因此通过修改相应目录下的 vld.ini 文件来定制 VLD 功能是最好的选择。当配置参数等号右边为空,或者给配置了不合法值时,在使用过程中会被程序重置到默认值。

2. 设置输出报告的编码格式

参数名ReportEncoding

有效赋值asciiunicode

默认值ascii

功能说明:设置输出报告的编码格式。默认是 ascii 编码,若改为 unicode 编码,控制台输出报告的同时会自动将报告输出到文本文件中(即使没有人为设置输出到文件)。由于调试器 Debugger 是不支持 unicode 字符的,所以这个配置只对显示的内存数据形式有影响,当泄露块中包含 unicode 字符时,这个配置的效果才能体现。若项目路径中含有 unicode 字符,ascii 编码时将无法显示调用堆栈信息,改为 unicode 有时候则能正常显示,详见 StackOverflow vld displays empty call stack

2.1 测试代码

#include <QCoreApplication>
#include "vld.h"

void testFun()

    QString str = QStringLiteral("汉字unicode");
    char *ptr = new char[30]();
    QByteArray Block = str.toLocal8Bit();
    memcpy(ptr, Block.constData(), Block.size());
    printf("ptr = %08x, *ptr = %s.\\n", ptr, ptr);


int main(int argc, char *argv[])

    QCoreApplication a(argc, argv);

    testFun();

    return a.exec();

测试环境:QT 5.9.2MSVC 2015 32bitDebug 模式,VLD 版本为 2.5.1,VLD 配置文件只对该参数做修改,测试工程所在路径为:E:\\Cworkspace\\Qt 5.9\\QtDemo\\testVLD

2.2 ReportEncoding = ascii 时的输出

标准输出窗显示:

ptr = 0119aa60, *ptr = 汉字unicode.

VLD 输出报告:

Visual Leak Detector read settings from: D:\\Program Files (x86)\\Visual Leak Detector\\vld.ini
Visual Leak Detector Version 2.5.1 installed.
WARNING: Visual Leak Detector detected memory leaks!
---------- Block 1 at 0x0119AA60: 30 bytes ----------
  Leak Hash: 0x7A25A79D, Count: 1, Total 30 bytes
  Call Stack (TID 2596):
    ucrtbased.dll!malloc()
    f:\\dd\\vctools\\crt\\vcstartup\\src\\heap\\new_array.cpp (15): testVLD.exe!operator new[]() + 0x9 bytes
    e:\\cworkspace\\qt 5.9\\qtdemo\\testvld\\main.cpp (7): testVLD.exe!testFun() + 0x10 bytes
    e:\\cworkspace\\qt 5.9\\qtdemo\\testvld\\main.cpp (19): testVLD.exe!main()
    f:\\dd\\vctools\\crt\\vcstartup\\src\\startup\\exe_common.inl (74): testVLD.exe!invoke_main() + 0x1B bytes
    f:\\dd\\vctools\\crt\\vcstartup\\src\\startup\\exe_common.inl (264): testVLD.exe!__scrt_common_main_seh() + 0x5 bytes
    f:\\dd\\vctools\\crt\\vcstartup\\src\\startup\\exe_common.inl (309): testVLD.exe!__scrt_common_main()
    f:\\dd\\vctools\\crt\\vcstartup\\src\\startup\\exe_main.cpp (17): testVLD.exe!mainCRTStartup()
    KERNEL32.DLL!BaseThreadInitThunk() + 0x19 bytes
    ntdll.dll!RtlGetAppContainerNamedObjectPath() + 0x11E bytes
    ntdll.dll!RtlGetAppContainerNamedObjectPath() + 0xEE bytes
  Data:
    BA BA D7 D6    75 6E 69 63    6F 64 65 00    00 00 00 00     ....unic ode.....
    00 00 00 00    00 00 00 00    00 00 00 00    00 00           ........ ........


Visual Leak Detector detected 1 memory leak (66 bytes).
Largest number used: 66 bytes.
Total allocations: 66 bytes.
Visual Leak Detector is now exiting.

2.3 ReportEncoding = unicode 时的输出

标准输出窗显示:

ptr = 0141bbe8, *ptr = 汉字unicode.

VLD 输出报告(控制台):

Visual Leak Detector read settings from: D:\\Program Files (x86)\\Visual Leak Detector\\vld.ini
Visual Leak Detector Version 2.5.1 installed.
NOTE: Visual Leak Detector: Unicode-encoded reporting has been enabled, but the
  debugger is the only selected report destination. The debugger cannot display
  Unicode characters, so the report will also be sent to a file. If no file has
  been specified, the default file name is ".\\memory_leak_report.txt".
    Generating a Unicode (UTF-16) encoded report.
    Outputting the report to the debugger and to E:\\Cworkspace\\Qt 5.9\\QtDemo\\build-testVLD-Desktop_Qt_5_9_2_MSVC2015_32bit-Debug\\memory_leak_report.txt
WARNING: Visual Leak Detector detected memory leaks!
---------- Block 1 at 0x0141BBE8: 30 bytes ----------
  Leak Hash: 0x7A25A79D, Count: 1, Total 30 bytes
  Call Stack (TID 20200):
    ucrtbased.dll!malloc()
    f:\\dd\\vctools\\crt\\vcstartup\\src\\heap\\new_array.cpp (15): testVLD.exe!operator new[]() + 0x9 bytes
    e:\\cworkspace\\qt 5.9\\qtdemo\\testvld\\main.cpp (7): testVLD.exe!testFun() + 0x10 bytes
    e:\\cworkspace\\qt 5.9\\qtdemo\\testvld\\main.cpp (19): testVLD.exe!main()
    f:\\dd\\vctools\\crt\\vcstartup\\src\\startup\\exe_common.inl (74): testVLD.exe!invoke_main() + 0x1B bytes
    f:\\dd\\vctools\\crt\\vcstartup\\src\\startup\\exe_common.inl (264): testVLD.exe!__scrt_common_main_seh() + 0x5 bytes
    f:\\dd\\vctools\\crt\\vcstartup\\src\\startup\\exe_common.inl (309): testVLD.exe!__scrt_common_main()
    f:\\dd\\vctools\\crt\\vcstartup\\src\\startup\\exe_main.cpp (17): testVLD.exe!mainCRTStartup()
    KERNEL32.DLL!BaseThreadInitThunk() + 0x19 bytes
    ntdll.dll!RtlGetAppContainerNamedObjectPath() + 0x11E bytes
    ntdll.dll!RtlGetAppContainerNamedObjectPath() + 0xEE bytes
  Data:
    BA BA D7 D6    75 6E 69 63    6F 64 65 00    00 00 00 00     ??湵捩摯e..
    00 00 00 00    00 00 00 00    00 00 00 00    00 00           ........


Visual Leak Detector detected 1 memory leak (66 bytes).
Largest number used: 66 bytes.
Total allocations: 66 bytes.
Visual Leak Detector is now exiting.

VLD 输出报告(文件 memory_leak_report.txt):

Visual Leak Detector Version 2.5.1 installed.
NOTE: Visual Leak Detector: Unicode-encoded reporting has been enabled, but the
  debugger is the only selected report destination. The debugger cannot display
  Unicode characters, so the report will also be sent to a file. If no file has
  been specified, the default file name is ".\\memory_leak_report.txt".
    Generating a Unicode (UTF-16) encoded report.
    Outputting the report to the debugger and to E:\\Cworkspace\\Qt 5.9\\QtDemo\\build-testVLD-Desktop_Qt_5_9_2_MSVC2015_32bit-Debug\\memory_leak_report.txt
WARNING: Visual Leak Detector detected memory leaks!
---------- Block 1 at 0x0141BBE8: 30 bytes ----------
  Leak Hash: 0x7A25A79D, Count: 1, Total 30 bytes
  Call Stack (TID 20200):
    ucrtbased.dll!malloc()
    f:\\dd\\vctools\\crt\\vcstartup\\src\\heap\\new_array.cpp (15): testVLD.exe!operator new[]() + 0x9 bytes
    e:\\cworkspace\\qt 5.9\\qtdemo\\testvld\\main.cpp (7): testVLD.exe!testFun() + 0x10 bytes
    e:\\cworkspace\\qt 5.9\\qtdemo\\testvld\\main.cpp (19): testVLD.exe!main()
    f:\\dd\\vctools\\crt\\vcstartup\\src\\startup\\exe_common.inl (74): testVLD.exe!invoke_main() + 0x1B bytes
    f:\\dd\\vctools\\crt\\vcstartup\\src\\startup\\exe_common.inl (264): testVLD.exe!__scrt_common_main_seh() + 0x5 bytes
    f:\\dd\\vctools\\crt\\vcstartup\\src\\startup\\exe_common.inl (309): testVLD.exe!__scrt_common_main()
    f:\\dd\\vctools\\crt\\vcstartup\\src\\startup\\exe_main.cpp (17): testVLD.exe!mainCRTStartup()
    KERNEL32.DLL!BaseThreadInitThunk() + 0x19 bytes
    ntdll.dll!RtlGetAppContainerNamedObjectPath() + 0x11E bytes
    ntdll.dll!RtlGetAppContainerNamedObjectPath() + 0xEE bytes
  Data:
    BA BA D7 D6    75 6E 69 63    6F 64 65 00    00 00 00 00     몺훗湵捩摯e..
    00 00 00 00    00 00 00 00    00 00 00 00    00 00           ........


Visual Leak Detector detected 1 memory leak (66 bytes).
Largest number used: 66 bytes.
Total allocations: 66 bytes.
Visual Leak Detector is now exiting.

2.4 输出结果对比

  • ReportEncoding = ascii 时,泄漏内存中的数据(汉字unicode)只有 unicode 显示正确,根据句点 . 的个数可知一行显示 16 个 ascii 字符。
  • ReportEncoding = unicode 时,报告会同时输出到生成目录下,默认文件名为 memory_leak_report.txt,根据句点 . 的个数可知一行显示 8 个 unicode 字符。奇怪的是,不论是在控制台中还是在文件中,泄漏内存中的汉字并没有按期望正常显示,只有最后一个字母 e 显示正确,这一现象产生的原因还未找到。对比控制台输出与文件输出,文件输出少了第一行 Visual Leak Detector read settings from: D:\\Program Files (x86)\\Visual Leak Detector\\vld.ini,泄漏数据的显示也略有差别,其他部分两者完全保持一致。

以上是关于Visual Leak DetectorRelease 模式下使用 VLD的主要内容,如果未能解决你的问题,请参考以下文章

Visual Leak Detector 报告 qt 库泄漏

Visual Leak Detector简介

Visual Leak Detector配置项 AggregateDuplicates

Visual Leak Detector配置项 StackWalkMethod

Visual Leak Detector安装 VLD

Visual Leak Detector配置项 TraceInternalFrames