天天看點

VC++記憶體洩漏檢測方法(5):使用強大的Windbg工具,重點是Symbols Path設定

前面4篇文章提到的方法,已經可以解決我們的大部分記憶體洩露問題了,但是這些方法是有前提的,那就是一定要有源代碼,而且還隻能是Debug版本調試模式下。實際上很多時候,我們的程式會用到第三方沒有源代碼的子產品,有些情況下子產品有記憶體洩露,但是沒有證據,又或者VC++ MFC退出提示有記憶體洩漏,但是資訊不足,不好定位是哪個檔案哪個函數出問題,我們該怎麼辦? 這時我們就要依靠無所不能的WinDbg了。

不了解windbg的讀者,請見我的另一篇部落格《Windows平台的Windbg/x64dbg/OllyDbg調試器》

Windows SDK v10

C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe

C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\windbg.exe

gflags.exe和windbg.exe在同一個安裝路徑

1、先運作Windbg安裝目錄下的gflags.exe,Image File,Image填exe名字,不要全路徑,選上Create user mode stack trace database;

VC++記憶體洩漏檢測方法(5):使用強大的Windbg工具,重點是Symbols Path設定

2、準備好Windows系統的環境變量,添加環境變量_NT_SYMBOL_PATH和_NT_ALT_SYMBOL_PATH,而_NT_SYMBOL_PROXY是可選項,非必需。

_NT_SYMBOL_PATH=C:\Symbols;srv*C:\Symbols*http://msdl.microsoft.com/download/symbols

_NT_ALT_SYMBOL_PATH=cache*C:\Symbols

_NT_SYMBOL_PROXY=127.0.0.1:8100

(1)這句話的意思是:指定用于符号解析的符号路徑為本地路徑C:\Symbols,如果找不到就去

http://msdl.microsoft.com/download/symbols

下載下傳,存放路徑是C:\Symbols。是以第1次斷點調試時,可能需要下載下傳等很久,第2次以後就不會了。

(2)一定要用C:\Symbols這個目錄,不要用自定義的目錄。否則會提示錯誤,如下:

*** ERROR: Symbol file could not be found.  Defaulted to export symbols for ntdll.dll -

VC++記憶體洩漏檢測方法(5):使用強大的Windbg工具,重點是Symbols Path設定

(3)考慮到.pdb符号檔案較大,為了給系統盤瘦身,不想把符号檔案放在C槽,那就可以采用mklink加入檔案連結的方法。用管理者權限打開CMD(windows開始菜單-所有程式-附件-指令提示符-右鍵,以管理者身份運作),輸入指令:

mklink /D C:\Symbols E:\software\Qt\symbolcache

這樣會在C槽建立連結C:\Symbols,它實際指向的是E盤自定義路徑。

(4)環境變量_NT_SYMBOL_PATH的設定不僅僅适用于WinDbg。實際上,所有調試器(至少Microsoft的VS調試器)都将使用此設定。VS2017的調試選項如圖:

VC++記憶體洩漏檢測方法(5):使用強大的Windbg工具,重點是Symbols Path設定
VC++記憶體洩漏檢測方法(5):使用強大的Windbg工具,重點是Symbols Path設定

之後我用VS調試器,因為第1次調試時已經下載下傳了符号檔案到本地,第2次及以後調試時,記得要去掉"Mincrosoft符号伺服器"的勾選,然後點選F5進入調試。但是我發現了一個問題,即狀态欄每次都提示從伺服器下載下傳并加載符合檔案,檔案很多還很慢。按理說,第1次調試時,符号檔案pdb不是已經下載下傳到本地磁盤了嗎?怎麼又要下載下傳?這是一個潛在的坑:

原來VS調試器運作過程中,它任何時候都會從windows伺服器加載;windows符号本地有了還仍然去svr查找;微軟伺服器符号加載如此之慢,竟然有時快有時慢!詳情見《微軟符号伺服器_NT_SYMBOL_PATH給VS調試帶來的隐藏坑》

解決方法有以下兩種(推薦方法2):

(1)到環境變量裡,删除或者重命名_NT_SYMBOL_PATH變量;

(2)到環境變量裡,設定_NT_SYMBOL_PROXY,指向一個無效的代理伺服器IP和Port;

重新開機VS,OK!!

3、運作Windbg.exe,(注意,32位程式請使用32位windbg調試,64位程式用64位windbg調試。)

(1)菜單File-Symbol File Path,或者Ctrl+S,彈框,請輸入使用者程式的.pdb符号檔案路徑(非必須,如果沒有pdb檔案則略過該步驟):

C:\Users\firecat\source\repos\SmartDispenser\Debug

加上之前已配置的環境變量_NT_SYMBOL_PATH,最終的符号檔案路徑會成為:

C:\Users\firecat\source\repos\SmartDispenser\Debug;C:\Symbols;srv*C:\Symbols*http://msdl.microsoft.com/download/symbols

windbg指令行的符号指令介紹:

.sympath #檢視符号目錄

.reload #重新加載符号目錄

!sym noisy #利用 !sym noisy 指令可以清楚發現 Symbols 安裝到底在哪裡出了問題

!heap #檢視堆棧

(2)菜單File-Open Executable-打開需要調試的exe檔案

(3)菜單Debug-Go,一步一步得運作

(4)exe在手動關閉退出時windbg會顯示記憶體洩漏:

Detected memory leaks!

Dumping objects ->

{194} normal block at 0x04091C20, 8 bytes long.

Data: <Ll y    > 4C 6C 86 79 01 CD CD CD

Object dump complete.

可以發現位址0x04091C20就是記憶體洩漏的位址,洩漏8個位元組,但是資訊仍不足,不好定位究竟是哪個檔案哪個函數出了問題,我們該怎麼辦?解決辦法如下:

通過!heap指令對該位址進行分析,可以發現具體的調用堆棧:

!heap -p -a 0x04091C20

VC++記憶體洩漏檢測方法(5):使用強大的Windbg工具,重點是Symbols Path設定
VC++記憶體洩漏檢測方法(5):使用強大的Windbg工具,重點是Symbols Path設定

通過這句提示,可以發現問題所在:

TKernel!TCollection_AsciiString::TCollection_AsciiString+0x00000036

繼續閱讀