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!\n";
    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
本博客的文章如無特殊說明,均為原創,轉載請注明出處。如未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM