天天看點

.Net 記憶體對象分析

在生産環境中,通過運作日志我們會發現一些異常問題,此時,我們不能直接拿VS遠端到伺服器上調試,同時日志輸出的資訊無法百分百反映記憶體中對象的狀态,比如說我們想檢視程序中所有的Socket連接配接狀态、服務路由資訊等等。

即:如何分析.Net 運作時記憶體對象?

是以,今天我們推薦.Net進階必備神器:Windbg,基于Windbg分析記憶體中對象的狀态。

還是以實際場景為例吧,這樣可以更加貼合實際應用,同時更有借鑒意義。

業務場景:分布式環境下,各個服務容器程序中緩存了各個服務的Socket連接配接資訊,友善運作時服務間互相通路。但是網絡是偶爾要抖動的,在抖動的一瞬間,很多Socket連接配接便中斷了,服務調用方收到的異常資訊便是:連接配接已中斷等。

如何快速定位到哪些Socket連接配接是中斷的?這些中斷的Socket連接配接是連接配接的哪些伺服器、端口?這些資訊可以幫助我們分析具體的網絡問題,同時做一些程式上的補償:連接配接重建。一個目标,保持程式的高可用性!

那麼,請出我們今天的主角:Windbg,微軟的官方介紹:

http://windbg.org/

進一步說,我們需要抓取指定程序某一瞬間的記憶體鏡像,然後使用Windbg分析記憶體中各種對象、線程、線程池、析構隊列、堆、CPU核心時間片等的狀态。

是以,第一步,我們需要對要進行記憶體分析的程序,抓取一個Full Dump檔案:記憶體鏡像檔案。

任務管理器->選擇程序->建立轉儲檔案

.Net 記憶體對象分析

系統會将Dump檔案存儲在指定的目錄,這個目錄需要拷貝一下,以備用。

第二步,從下面路徑下載下傳并安裝Windbg:

https://developer.microsoft.com/en-us/windows/hardware/download-windbg

.Net 記憶體對象分析

請根據作業系統的位數,選擇X86或者X64。這裡我們用的64位作業系統,選擇的Windbg(X64)

第三步:Ctrl+D,打開剛才抓取的Dump檔案

.Net 記憶體對象分析
.Net 記憶體對象分析
第四步:加載調試用的SOS.dll: .loadby sos clr

.loadby sos clr      
.Net 記憶體對象分析

第五步:檢視記憶體中指定類型的對象 

!dumpheap -Type Socket      

這裡的Socket是具體的類型,我們要檢視Socket連接配接狀态,是以類型是Socket

.Net 記憶體對象分析

這裡的Header中MT=Method Table

我們需要用的MT:00007ffafe50d700

第六步,檢視記憶體所有所有的Socket對象的位址:

!dumpheap -mt 00007ffafe50d700      
.Net 記憶體對象分析

輸出結果中,第一列是某一個Socket對象的記憶體位址

此時,我們可以使用下面的指令,随機檢視一個Socket對象的資訊:

!do 000001b2d188ae00      

!do 的意思:!dumpObj 

.Net 記憶體對象分析

 那麼問題來了,幾百個Socket對象,如果一個一個!do檢視,這工作量太大了! 當然不能這麼幹,Windbg有.foreach指令

 搜尋Debugging help.chm文檔,.foreach給了個樣例:

.foreach /f ( place "g:\myfile.txt") { dds place }       

即,循環周遊一個文本檔案,對每一行資料,執行一個指令操作。

好,我們回到我們上一步的輸出中:每個Socket對象的位址清單,我們拷貝出來,用文本編輯工具隻取出第一列(Socket位址列),儲存成1.txt

第七步:循環周遊檢視每個記憶體對象

.foreach /f (adr "C:\1.txt") {!do adr}      

輸出:

.Net 記憶體對象分析

将所有的輸出,拷貝到文本編輯器中,搜尋查詢指定的屬性,例如m_IsConnected=0, 即可找出連接配接斷開的Socket對象,然後進一步用!gcroot 檢視這個對象的引用關系,再一步一步看各個引用對象的資訊就可以大緻分析了。

以上就是.Net 記憶體對象分析的整個過程,分享給大家。

周國慶

2017/10/06