一個Qt5+VS2017的工程,須要進行串口操做,在自動時發現一段時間軟件崩潰了,沒有保存log,在 debug 的時候發現每運行一次應用佔據的內存就多一點,後來意識到是內存泄漏了。這個真是頭疼,變量太多,不知道從哪裏查找內存泄漏好。因而迫切的須要找到一種追查內存泄漏的工具。html
一開始很天然的是vs2017 debug查看內存佔用狀況,採用的就是這個博文 https://blog.csdn.net/luoyu510183/article/details/84728664的思路,然而太麻煩了,放棄。後來無心中發現 Visual Leak Detector 這個工具,簡直完美了。ios
官網介紹說 VLD 時一個免費的、健壯的、開源的針對 Visual C++ 的內存泄漏檢測系統。
使用方式很是簡單,在安裝以後,只須要告訴 Visual C++ 頭文件路徑和庫文件。只須要在源文件中添加一行代碼便可使用 #include <vld.h>
.
在 Visual Studio debugger 運行的時候, VLD 會在 debug 會話結束以後把檢測報告打印到輸出窗口。內存泄漏報告包括完整的調用堆棧顯示內存庫是如何分配的。雙擊調用堆棧上的行號便可以跳轉到編輯器對應的文件行。c++
Visual Leak Detector 官網地址 https://archive.codeplex.com/?p=vld,它已經遷移到了 github 。git
不湊巧的是官網更新到2015年,支持vs2015,因此只能從源碼開始編譯 vld 了。能夠從官網或者 github 下載源碼。github
前面說了源碼只支持 vs2015,用 vs2017 一打開就出現了問題,源碼最高支持 vs2015 編譯器,以下圖所示:redis
上面的這個問題,通常只須要從新定位編譯器便可,鼠標右鍵 "dynamic" 目標在彈出的選項中選擇 "Retarget Projects",雖然 輸出窗口顯示操做成功了,可是實際並無。編輯器
這是由於平臺工具集不對,須要手動修改每一編譯目標的平臺工具集,這裏以 dynamic 編譯目標爲例,修改它的屬性,以下圖所示:ide
在 General-->Platform Toolset
中從新選擇,若是有多個選擇,請選擇一個合適的工具集,這裏選擇 Visual Studio 2017 (v141)。(其餘的編譯目標執行同樣的操做。)工具
在編譯以前須要把 "win32" 改爲 "x64",由於個人電腦是64位的,應用環境也是64位的。而後 Build Solution。而後就出現了 「Windows SDK 8.1」 error。ui
按照提示,選擇 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,雙擊這個提示跳轉到源碼 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
其餘的編譯目標出現相同的問題,採用相同的解決方法。
上一步編譯以後提示以下,跳轉到對應的源文件 vld.cpp
第 976 行:
很明顯這是由於 vs2017 對應的版本號是 1916,因此修改成 _MSC_VER > 1916
便可。
vld.lib
上一步編譯以後提示找不到庫文件 vld.lib
例如這個工程編譯產生 lib 文件夾內容以下:
須要向報錯的工程中添加庫文件路徑和庫文件,可是這麼多編譯目標,一個一個設置庫文件路徑和庫文件名,煩都煩死了,因此新建一個 property sheet,而後每個工程添加這個屬性就能夠了。
新建的 property sheet 內容以下
每個找不到 vld.lib
的編譯項目都添加這個屬性就能夠了。
========== Rebuild All: 16 succeeded, 0 failed, 0 skipped ==========
一個最簡單的示例,代碼以下:
#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 目錄,從新啓動調試,又出幺蛾子了。
解決方法參見這篇博文 https://blog.csdn.net/u012248603/article/details/52639578,
只須要把 vld 工程生成目錄中的兩個文件 dbghelp.dll 和 Microsoft.DTfW.DHL.manifest 拷貝到這個工程的 debug 目錄便可。固然還須要把配置文件 vld.ini 拷貝到這個目錄,並作修改,最後附上這個配置文件內容。
參見這個博文 https://blog.csdn.net/fwb330198372/article/details/84253292
須要修改設置選項, Linker-->debugging-->"Generate Debug Info" 設置爲 /Debug:FULL 便可。
如下就是這個工程的VLD追蹤內存泄漏的截圖:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; 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
出處:http://www.javashuo.com/article/p-priivxgi-cv.html 本博客的文章如無特殊說明,均爲原創,轉載請註明出處。如未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。