• VS2017 编译 Visual Leak Detector + VLD 使用示例


    起因

    一个Qt5+VS2017的工程,需要进行串口操作,在自动时发现一段时间软件崩溃了,没有保存log,在 debug 的时候发现每运行一次应用占据的内存就多一点,后来意识到是内存泄漏了。这个真是头疼,变量太多,不知道从哪里查找内存泄漏好。于是迫切的需要找到一种追查内存泄漏的工具。

    一开始很自然的是vs2017 debug查看内存占用情况,采用的就是这个博文 https://blog.csdn.net/luoyu510183/article/details/84728664的思路,然而太麻烦了,放弃。后来无意中发现 Visual Leak Detector 这个工具,简直完美了。

    VLD 简介

    官网介绍说 VLD 时一个免费的、健壮的、开源的针对 Visual C++ 的内存泄漏检测系统。
    使用方式非常简单,在安装之后,只需要告诉 Visual C++ 头文件路径和库文件。只需要在源文件中添加一行代码即可使用 #include <vld.h>.
    在 Visual Studio debugger 运行的时候, VLD 会在 debug 会话结束之后把检测报告打印到输出窗口。内存泄漏报告包括完整的调用堆栈显示内存库是如何分配的。双击调用堆栈上的行号即可以跳转到编辑器对应的文件行。

    Visual Leak Detector 官网地址 https://archive.codeplex.com/?p=vld,它已经迁移到了 github

    VS2017编译VLD

    不凑巧的是官网更新到2015年,支持vs2015,所以只能从源码开始编译 vld 了。可以从官网或者 github 下载源码。

    解决编译问题

    前面说了源码只支持 vs2015,用 vs2017 一打开就出现了问题,源码最高支持 vs2015 编译器,如下图所示:

    支持vs2017编译器

    上面的这个问题,一般只需要重新定位编译器即可,鼠标右键 "dynamic" 目标在弹出的选项中选择 "Retarget Projects",虽然 输出窗口显示操作成功了,但是实际并没有。

    这是因为平台工具集不对,需要手动修改每一编译目标的平台工具集,这里以 dynamic 编译目标为例,修改它的属性,如下图所示:

    General-->Platform Toolset 中重新选择,如果有多个选择,请选择一个合适的工具集,这里选择 Visual Studio 2017 (v141)。(其他的编译目标执行一样的操作。)

    变更为 x64 工程

    在编译之前需要把 "win32" 改成 "x64",因为我的电脑是64位的,应用环境也是64位的。然后 Build Solution。然后就出现了 “Windows SDK 8.1” error。

    按照提示,选择 Retarget Projects 然后选择最先的SDK版本,然后对其他的编译目标执行相同的操作。

    定义宏 _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING

    编译,又出幺蛾子了,提示 _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING 定义这个宏可以避免错误,所以需要执行如下的操作:

    打开工程 libgtest 的属性设置界面,C++-->Precoessor-->Processor Definitions 中添加一个宏定义: _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING

    对其他的编译目标执行相同的操作,然后编译。

    Unsupported compiler

    执行上面的操作之后编译提示 Unsupported compiler,双击这个提示跳转到源码 allocs.cpp 第37行,跳到 _MSC_VER 定义的地方一看,原来 vs 2017 的版本是 1916,同时搜索一下本地电脑上 Microsoft SDK 是否包含 ucrtbased.dll 或者 msvcr120d.dll,经过查找 VS2017 确实包含的是 ucrtbased.dll,新的定义如下:

    #elif _MSC_VER == 1800	// VS 2013
    #define CRTDLLNAME   _T("msvcr120d.dll")
    #elif _MSC_VER == 1900	// VS 2015
    #define CRTDLLNAME   _T("ucrtbased.dll")
    #elif _MSC_VER == 1916	// VS 2017
    #define CRTDLLNAME   _T("ucrtbased.dll")
    #else
    #error Unsupported compiler
    #endif
    

    其他的编译目标出现相同的问题,采用相同的解决方法。

    Not supported VS

    上一步编译之后提示如下,跳转到对应的源文件 vld.cpp 第 976 行:

    很明显这是因为 vs2017 对应的版本号是 1916,所以修改为 _MSC_VER > 1916 即可。

    cannot open file vld.lib

    上一步编译之后提示找不到库文件 vld.lib

    例如这个工程编译产生 lib 文件夹内容如下:

    需要向报错的工程中添加库文件路径和库文件,但是这么多编译目标,一个一个设置库文件路径和库文件名,烦都烦死了,所以新建一个 property sheet,然后每一个工程添加这个属性就可以了。

    新建的 property sheet 内容如下

    每一个找不到 vld.lib 的编译项目都添加这个属性就可以了。

    编译通过

    ========== Rebuild All: 16 succeeded, 0 failed, 0 skipped ==========

    VLD 最简单示例

    一个最简单的示例,代码如下:

    #include "pch.h"
    #include <iostream>
    #if _DEBUG
    #include "vld.h"
    #endif
    int main()
    {
        int *pint100 = new int[100];
        std::cout << "Hello World!
    ";
        short *pshort100 = new short[100];
    }
    

    在编译之前需要确保是 Debug, x64,并且把上面的 property sheet 拷贝到当前目录,并且添加到这个工程中,编译运行,弹出了“无法找到 vld_x64.dll ”的错误,简单,拷贝上面的工程产生的 vld_x64.dll到这个工程的 Debug 目录,重新启动调试,又出幺蛾子了。

    无法启动, 0xc0150002

    解决方法参见这篇博文 https://blog.csdn.net/u012248603/article/details/52639578
    只需要把 vld 工程生成目录中的两个文件 dbghelp.dllMicrosoft.DTfW.DHL.manifest 拷贝到这个工程的 debug 目录即可。当然还需要把配置文件 vld.ini 拷贝到这个目录,并做修改,最后附上这个配置文件内容。

    VLD不显示行号

    参见这个博文 https://blog.csdn.net/fwb330198372/article/details/84253292

    需要修改设置选项, Linker-->debugging-->"Generate Debug Info" 设置为 /Debug:FULL 即可。

    以下就是这个工程的VLD追踪内存泄漏的截图:

    vld.ini 配置文件

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;
    ;;  Visual Leak Detector - Initialization/Configuration File
    ;;  Copyright (c) 2005-2017 VLD Team
    ;;
    ;;  This library is free software; you can redistribute it and/or
    ;;  modify it under the terms of the GNU Lesser General Public
    ;;  License as published by the Free Software Foundation; either
    ;;  version 2.1 of the License, or (at your option) any later version.
    ;;
    ;;  This library is distributed in the hope that it will be useful,
    ;;  but WITHOUT ANY WARRANTY; without even the implied warranty of
    ;;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    ;;  Lesser General Public License for more details.
    ;;
    ;;  You should have received a copy of the GNU Lesser General Public
    ;;  License along with this library; if not, write to the Free Software
    ;;  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    ;;
    ;;  See COPYING.txt for the full terms of the GNU Lesser General Public License.
    ;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    ; Any options left blank or not present will revert to their default values.
    [Options]
    
    ; The main on/off switch. If off, Visual Leak Detector will be completely
    ; disabled. It will do nothing but print a message to the debugger indicating
    ; that it has been turned off.
    ;
    ;  Valid Values: on, off
    ;  Default: on
    ;
    VLD = on
    
    ; If yes, duplicate leaks (those that are identical) are not shown individually.
    ; Only the first such leak is shown, along with a number indicating the total
    ; number of duplicate leaks.
    ;
    ;   Valid Values: yes, no
    ;   Default: no
    ;
    AggregateDuplicates = yes
    
    ; Lists any additional modules to be included in memory leak detection. This can
    ; be useful for checking for memory leaks in debug builds of 3rd party modules
    ; which can not be easily rebuilt with '#include "vld.h"'. This option should be
    ; used only if absolutely necessary and only if you really know what you are
    ; doing.
    ;
    ;   CAUTION: Avoid listing any modules that link with the release CRT libraries.
    ;     Only modules that link with the debug CRT libraries should be listed here.
    ;     Doing otherwise might result in false memory leak reports or even crashes.
    ;
    ;   Valid Values: Any list containing module names (i.e. names of EXEs or DLLs)
    ;   Default: None.
    ;
    ForceIncludeModules = 
    
    ; Maximum number of data bytes to display for each leaked block. If zero, then
    ; the data dump is completely suppressed and only call stacks are shown.
    ; Limiting this to a low number can be useful if any of the leaked blocks are
    ; very large and cause unnecessary clutter in the memory leak report.
    ;
    ;   Value Values: 0 - 4294967295
    ;   Default: 256
    ;
    MaxDataDump = 
    
    ; Maximum number of call stack frames to trace back during leak detection.
    ; Limiting this to a low number can reduce the CPU utilization overhead imposed
    ; by memory leak detection, especially when using the slower "safe" stack
    ; walking method (see StackWalkMethod below).
    ;
    ;   Valid Values: 1 - 4294967295
    ;   Default: 64
    ;
    MaxTraceFrames = 
    
    ; Sets the type of encoding to use for the generated memory leak report. This
    ; option is really only useful in conjuction with sending the report to a file.
    ; Sending a Unicode encoded report to the debugger is not useful because the
    ; debugger cannot display Unicode characters. Using Unicode encoding might be
    ; useful if the data contained in leaked blocks is likely to consist of Unicode
    ; text.
    ;
    ;   Valid Values: ascii, unicode
    ;   Default: ascii
    ;
    ReportEncoding = ascii
    
    ; Sets the report file destination, if reporting to file is enabled. A relative
    ; path may be specified and is considered relative to the process' working
    ; directory.
    ;
    ;   Valid Values: Any valid path and filename.
    ;   Default: .memory_leak_report.txt
    ;
    ReportFile = 
    
    ; Sets the report destination to either a file, the debugger, or both. If
    ; reporting to file is enabled, the report is sent to the file specified by the
    ; ReportFile option.
    ;
    ;   Valid Values: debugger, file, both
    ;   Default: debugger
    ;
    ReportTo = both
    
    ; Turns on or off a self-test mode which is used to verify that VLD is able to
    ; detect memory leaks in itself. Intended to be used for debugging VLD itself,
    ; not for debugging other programs.
    ;
    ;   Valid Values: on, off
    ;   Default: off
    ;
    SelfTest = off
    
    ; Selects the method to be used for walking the stack to obtain stack traces for
    ; allocated memory blocks. The "fast" method may not always be able to
    ; successfully trace completely through all call stacks. In such cases, the
    ; "safe" method may prove to more reliably obtain the full stack trace. The
    ; disadvantage is that the "safe" method is significantly slower than the "fast"
    ; method and will probably result in very noticeable performance degradation of
    ; the program being debugged.
    ;
    ;   Valid Values: fast, safe
    ;   Default: fast
    ; 
    StackWalkMethod = fast
    
    ; Determines whether memory leak detection should be initially enabled for all
    ; threads, or whether it should be initially disabled for all threads. If set
    ; to "yes", then any threads requiring memory leak detection to be enabled will
    ; need to call VLDEnable at some point to enable leak detection for those
    ; threads.
    ;
    ;   Valid Values: yes, no
    ;   Default: no
    ;
    StartDisabled = no
    
    ; Determines whether or not all frames, including frames internal to the heap,
    ; are traced. There will always be a number of frames internal to Visual Leak
    ; Detector and C/C++ or Win32 heap APIs that aren't generally useful for
    ; determining the cause of a leak. Normally these frames are skipped during the
    ; stack trace, which somewhat reduces the time spent tracing and amount of data
    ; collected and stored in memory. Including all frames in the stack trace, all
    ; the way down into VLD's own code can, however, be useful for debugging VLD
    ; itself.
    ;
    ;   Valid Values: yes, no
    ;   Default: no
    ;
    TraceInternalFrames = no
    
    ; Determines whether or not report memory leaks when missing HeapFree calls.
    ;
    ;   Valid Values: yes, no
    ;   Default: no
    ;
    SkipHeapFreeLeaks = no
    
    ; Determines whether or not report memory leaks generated from crt startup code.
    ; These are not actual memory leaks as they are freed by crt after the VLD object
    ; has been destroyed.
    ;
    ;   Valid Values: yes, no
    ;   Default: yes
    ;
    SkipCrtStartupLeaks = yes
    
    

    声明

    欢迎转载,请注明出处和作者,同时保留声明。
    作者:LinTeX9527
    出处:https://www.cnblogs.com/LinTeX9527/p/11127319.html
    本博客的文章如无特殊说明,均为原创,转载请注明出处。如未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    GAE 随机获取实体
    纵观 jBPM:从 jBPM3 到 jBPM5 以及 Activiti5
    NetBeans 时事通讯(刊号 # 131 Jan 04, 2011)
    发现 Google Buzz 与 Google Code 进行了集成
    改良程序的 11 技巧
    《让子弹飞》向我们展现真实的革命
    有关STL中的容器和MFC的集合类型构造函数区别的一点思考
    GAE 随机获取实体
    改良程序的 11 技巧
    NetBeans 时事通讯(刊号 # 132 Jan 11, 2011)
  • 原文地址:https://www.cnblogs.com/LinTeX9527/p/11127319.html
Copyright © 2020-2023  润新知