目錄
1、概述
2、使用Windbg監測記憶體泄露的一般步驟
3、詳解整個操作程序
3.1、gflags.exe和umdh.exe介紹
3.2、啟動cmd命令列
3.3、設定pdb符號庫路徑
3.4、呼叫gflags設定啟用udmh.exe的堆疊跟蹤
3.5、第一次使用umdh抓取堆記憶體使用快照
3.6、第二次使用umdh抓取堆記憶體使用快照
3.7、比較兩次堆記憶體使用快照,得出結論
4、Windbg分析記憶體泄露的不足
最近有個客戶那邊使用我們的Windows軟體時又遇到了記憶體泄露的問題,軟體在客戶的機器環境上運行半個多小時后就會出現閃退崩潰,去年我們也遇到過類似的問題,很大概率是第三方安全軟體導致的,第三方安全的有庫注入到我們的行程中,應該是注入的庫有記憶體泄露,導致我們行程出現問題,本文簡單講述一下如何使用Windbg來定位Windows程式中的記憶體泄露問題,
1、概述
Windows平臺上分析記憶體泄露的工具有很多,比如Rational Purify、BoundsChecker等,但是這些工具現在已經好幾年不再維護了,已經不再兼容較新的Visual Studio版本了,即便能兼容也是比較麻煩的,比如BoundsChecker就需要將頭檔案和庫添加到工程中重新編譯程式,大型軟體中包含了多個模塊,在不確定發生記憶體泄露的模塊時,讓所有模塊都添加BoundsChecker的檔案重新編譯一下也不切實際,
我們需要一個工具,在不需要重新編譯程式的情況下,能直接去動態的分析程式是否存在記憶體泄露,之前一直在尋找這樣的工具,一直沒有找到合適的,使用過騰訊的tMemoryMonitor記憶體監測工具,但該工具并不好用,很多實際場景下的記憶體泄露都監測不到,
最后只能使用Windbg去檢測記憶體泄露,Windbg是微軟提供的Windows下強大的除錯工具,可以分析多種軟體例外問題,在我們日常開發程序中會頻繁地使用到該工具,但之前使用Windbg監測記憶體泄露問題還是第一次,目前我們已經使用Windbg定位了好幾起記憶體泄露的問題,Windbg還是比較給力的,
2、使用Windbg監測記憶體泄露的一般步驟
在監測之前,需要安裝新版本的Windbg,因為我們實際上是使用Windbg安裝目錄下的gflags.exe和umdh.exe兩個程式去完成監測的,
新版本的Windbg已經合并到Windows SDK包中,要安裝Windbg,則需要下載Windows SDK開發包,在安裝時可以選擇只安裝Windbg,操作起來有點小麻煩,我已經將10.0版本的Windbg安裝包上傳至CSDN上了,直接去下載安裝即可,其鏈接為:https://download.csdn.net/download/chenlycly/34256522https://download.csdn.net/download/chenlycly/34256522
https://download.csdn.net/download/chenlycly/34256522
使用gflags.exe和umdh.exe監測記憶體泄露的一般不走如下:
1)右鍵以管理員權限運行cmd命令列視窗,用cd命令,切換到windbg的安裝目錄中,比如我的安裝路徑是:C:\Program Files\Windows Kits\10\Debuggers\x86,
2)在cmd中輸入:gflags /i XXX.exe +ust
3)在cmd中輸入:umdh.exe -pn:XXX.exe -f:E:\log1.txt,等待命令執行完成
4)讓軟體運行一會,操作軟體使之產生記憶體泄露
5)在cmd中輸入:umdh.exe -pn:XXX.exe -f:E:\log2.txt,等待命令執行完成
6)在cmd中輸入:umdh.exe E:\log1.txt E:\log2.txt -f:E:\result.txt,等待命令執行完成
7)查看result.txt檔案中的堆記憶體使用變化的統計,定位問題,
3、詳解整個操作程序
3.1、gflags.exe和umdh.exe介紹
gflags.exe和umdh.exe是新版本Windbg安裝路徑下的程式,
gflags.exe (Global Flags) ,全域標志編輯器 ,用來啟用和禁用高級除錯、診斷和故障排除功能, 它通常用于打開其他工具跟蹤、計數和日志的指示器,可以通過命令列執行其相關的操作,也可以在gflags的UI界面上設定:

umdh.exe(User-Mode Dump Heap),用戶轉儲堆程式,用來捕獲并分析行程的堆記憶體分配, 對于每個分配,umdh顯示分配的大小、開銷的大小、指向分配的指標和分配堆疊, 如果行程具有多個活動記憶體堆,umdh將捕獲所有堆, 此分析可以實時顯示,也可以保存在日志檔案中,該工具程式是沒有UI界面的,是通過cmd命令列執行操作的,
3.2、啟動cmd命令列
一般我們需要右鍵以管理員權限運行cmd命令列視窗,特別是在Win10系統中,然后用cd命令,切換到windbg的安裝目錄中,比如我的安裝路徑是:C:\Program Files\Windows Kits\10\Debuggers\x86,以方便接下來呼叫gflags.exe和umdh.exe兩個程式,
3.3、設定pdb符號庫路徑
最侄訓分析出使用堆記憶體的函式呼叫堆疊,為了方便查看到函式呼叫堆疊中的具體函式,可以設定pdb符號庫檔案路徑,我們可以在命令列中設定如下的環境變數:
set _NT_SYMBOL_PATH="D:\MySymbols;srv*C:\WINDOWS\Symbols*http://msdl.microsoft.com/download/symbols"
環境變數的名稱為_NT_SYMBOL_PATH,其值是包含pdb的路徑,路徑包含兩部分,前半部分的D:\MySymbols是我們軟體中的符號庫檔案,后半部分則是微軟系統在線的符號庫路徑,
如果不想設定微軟在線pdb路徑,可以只設定程式自己的pdb檔案也可以,出來在命令列中添加環境變數,也可以在系統中添加環境變數,以win10系統為例,在系統搜索欄搜索環境變數,找到編輯環境變數的入口,依次操作即可:



3.4、呼叫gflags設定啟用udmh.exe的堆疊跟蹤
繼續在cmd命令列中輸入:
gflags /i XXX.exe +ust
其中/i用來指定目標行程的名稱,引數ust的含義是:Create user mode stack trace database,此命令用來給目標行程創建用戶模式堆疊跟蹤資料庫,
3.5、第一次使用umdh抓取堆記憶體使用快照
繼續在cmd命令列中輸入:
umdh.exe -pn:XXX.exe -f:E:\log1.txt
其中-pn引數用來指定目標行程的行程名,-f引數用來指定存放抓取來的堆記憶體使用快照資料資訊,此命令運行后,將第一次抓取的堆記憶體使用快照資料保存到E:\log1.txt中,
輸入該命令后,讓程式運行一會,盡可能運行的時間長一會,保證在這段時間內產生足夠多的記憶體泄露,這樣windbg的監測結果更準確一點,
3.6、第二次使用umdh抓取堆記憶體使用快照
繼續在cmd中輸入如下的命令:
umdh.exe -pn:XXX.exe -f:E:\log2.txt
命令決議同上,此命令運行后,將第二次抓取的堆記憶體使用快照資料保存到E:\log2.txt中,
3.7、比較兩次堆記憶體使用快照,得出結論
最后在cmd中輸入:
umdh.exe E:\log1.txt E:\log2.txt -f:E:\result.txt
即比較log1.txt 和log2.txt兩檔案中的堆記憶體使用變化量,得出統計資料,將統計結果保存到E:\result.txt檔案中,打開E:\result.txt,即可查看到堆記憶體的變化情況,按堆記憶體申請數量從高到底排列,每一項統計結果都有詳細的函式呼叫堆疊,一般我們只需要分析使用量較高的幾項即可,一般第一項就是發生記憶體泄露的堆疊,比如:

4、Windbg分析記憶體泄露的不足
Windbg只能監測兩個時間點的申請堆記憶體的變化量,并沒有去統計釋放的堆記憶體,這一點和Linux上排查記憶體泄露的神器Valgrind要差一些,所以Windbg統計出來的結果中,排在第一位的項可能并不是記憶體泄露的項,需要我們去過濾排名較高的幾項,最終定位出發生記憶體泄露的那一項,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/356988.html
標籤:其他
上一篇:資料結構——佇列的實作
