.NET调试学习
診斷工具
動手實現(xiàn)一個適用于.NET Core 的診斷工具
Dump
dump在計算機科學中是一個廣泛運用的動詞、名詞。
作為動詞:一般指將數(shù)據(jù)導出、轉存成文件或靜態(tài)形式。比如可以理解成:把內(nèi)存某一時刻的內(nèi)容,dump(轉存,導出,保存)成文件。
作為名詞:一般特指上述過程中所得到的文件或者靜態(tài)形式。
1、為什么要dump(dump的目的)?
因為程序在計算機中運行時,在內(nèi)存、CPU、I/O等設備上的數(shù)據(jù)都是動態(tài)的(或者說是易失的),也就是說數(shù)據(jù)使用完或者發(fā)生異常就會丟掉。如果我想得到某些時刻的數(shù)據(jù)(有可能是調(diào)試程序Bug或者收集某些信息),就要把他轉儲(dump)為靜態(tài)(如文件)的形式。否則,這些數(shù)據(jù)你永遠都拿不到。
2、dump轉儲的是什么內(nèi)容(dump的對象)?
其實上邊已經(jīng)提到了,就是將動態(tài)(易失)的數(shù)據(jù),保存為靜態(tài)的數(shù)據(jù)(持久數(shù)據(jù))。像程序這種本來就保存在存儲介質(如硬盤)中的數(shù)據(jù),也就沒有必要dump。
常出現(xiàn)dump的場景:Unix/Linux中的coredump,Java中的headdump和threaddump。
.NET程序崩潰了怎么抓 Dump ? 我總結了三種方案
WinDbg調(diào)式
1、理論學習
.NET高級調(diào)試系列-Windbg調(diào)試入門篇
WinDbg:Windows 調(diào)試工具(WinDbg、KD、CDB、NTSD)
win10上安裝后目錄:C:Program Files (x86)Windows Kits10Debuggersx64
Windbg是Microsoft公司免費調(diào)試器調(diào)試集合中的GUI的調(diào)試器,支持Source和Assembly兩種模式的調(diào)試。Windbg不僅可以調(diào)試應用程序,還可以進行Kernel Debug。結合Microsoft的Symbol Server,可以獲取系統(tǒng)符號文件,便于應用程序和內(nèi)核的調(diào)試。Windbg支持的平臺包括X86、IA64、AMD64。雖然windbg也提供圖形界面操作,但它最強大的地方還是有著強大的調(diào)試命令,一般情況會結合GUI和命令行進行操作,常用的視圖有:局部變量、全局變量、調(diào)用棧、線程、命令、寄存器、白板等。其中“命令”視圖是默認打開的。
Windbg在用戶態(tài)和內(nèi)核態(tài)下,都支持兩種調(diào)試模式,即“實時調(diào)試模式(Living)”和“事后調(diào)試模式(Postmortem)”。
所謂實時模式,是被調(diào)試的目標對象(Target)當前正在運行當中,調(diào)試器可以實時分析、修改被調(diào)試目標的狀態(tài),如寄存器、內(nèi)存、變量,調(diào)試exe可執(zhí)行程序或雙機實時調(diào)試都屬于這種模式;
所謂事后模式,是被調(diào)試的目標對象(Target)已經(jīng)結束了,現(xiàn)在只是事后對它保留的快照進行分析,這個快照稱為轉儲文件(Dump文件)。
Windbg另一個重大優(yōu)點,還在于它支持源碼級的調(diào)試,就像VC自帶的調(diào)試器一樣。雖然提供了用戶界面,但Windbg歸根結底還是需要用戶一個個地輸入命令來指揮其行動。這就是他的Command窗口。每個調(diào)試命令都各有使用范圍,有些命令只能用于內(nèi)核調(diào)試,有些命令只能用于用戶調(diào)試,有些命令只能用于活動調(diào)試。但用戶也不必記得這許多,一旦在某個環(huán)境下,使用了不被支持的命令,都會顯示“No export XXX found”的字樣。
官網(wǎng):WinDbg 入門(用戶模式)
其他參考:
WinDbg的安裝、配置和功能(系列博文)使用WinDbg調(diào)試入門(用戶模式)
一步一個坑 - WinDbg調(diào)試.NET程序
Windbg命令相關
WinDbg 命令三部曲:(一)WinDbg 命令手冊
WinDbg 命令三部曲:(二)WinDbg SOS 擴展命令手冊
!DumpHeap 將遍歷 GC 堆對對象進行分析。通過指定不同的選項,可以查看特定的類型、數(shù)組和鎖。
!GCRoot [-nostacks] <Object address> 查詢一個對象的所有引用根。
!syncblk看看有沒有 lock 的情況
!DumpStack Objects 顯示當前調(diào)用棧上的所有托管對象的信息,可配合 k 或 CLRStack 命令使用
!clrstack 看調(diào)用棧
!eeheap -gc命令,看下托管堆大小【即遍歷進程內(nèi)存中的 CLR 數(shù)據(jù)結構】
!eeheap -loader命令,看下loader 堆大小(非托管)
WinDbg 命令三部曲:(三)WinDbg SOSEX 擴展命令手冊
用sosex擴展的!dlk命令可以自動檢索是否有死鎖
2、概念原理之:什么是SOS、mscordacwks
參考:windbg分析dump-解決mscorwks不匹配
mscorwks:通用語言運行時 (CLR) 是執(zhí)行托管代碼的 Microsoft .NET 框架的核心引擎。mscorwks.dll是CLR 2.0實現(xiàn)的主要文件。此引擎在本機代碼中實現(xiàn)。
SOS:SOS.DLL可以提供關于CLR的信息,幫助我們在vs和windbg調(diào)試托管程序。例如,可以顯示有關托管堆的信息、查找堆損壞情況、顯示運行時使用的內(nèi)部數(shù)據(jù)類型以及查看有關運行時內(nèi)運行的所有托管代碼的信息。
mscorwks使用本機代碼實現(xiàn)了CLR,SOS可以提供托管的CLR信息,而mscordacwks即為連接本機代碼和托管代碼之間的橋。SOS無需了解CLR底層細節(jié)。
官網(wǎng):SOS.dll (SOS debugging extension)
3、Windbg話題
Windbg From 一線碼農(nóng)聊技術
幾個分析思路:
內(nèi)存泄漏:首先就要排查到底是托管堆還是非托管堆的問題 ,參考:記一次 .NET 某HIS系統(tǒng)后端服務 內(nèi)存泄漏分析
實踐
如何在 .NET 程序萬種死法中有效的生成 Dump
如何在 .NET 程序萬種死法中有效的生成 Dump
用Windbg打開生成的Dump文件【用vs也可以打開dmp文件進行分析】
執(zhí)行命令如下:
!address -summary 查看當前 process 的內(nèi)存占用量
!dumpheap -stat -min 1024 尋找大對象(單位Byte),在托管堆中
!dumpheap-typeSystem.String-min10240 用-type屬性篩選出>10k的字符串。
!gcroot4a855060 【參數(shù)是 MT對應的任意一個address】
如何在 NET 程序萬種死法中有效的生成 Dump (下)
以下是一些說明:
ProcDump生成Dump文件
ProcDump使用
procdumpConsoleApp2-m1024-maE:
et5ConsoleApp1ConsoleApp2inDebug
如果你的機器有多個 ConsoleApp2,可以將其替換成 pid(進程id)
報錯error opening
是需要使用管理員命令提示符才能成功抓取dump
官網(wǎng)
ProDump是跨平臺的命令行工具,可以在指定的條件下生成dump文件。
應用場景:主要用于高CPU占用率的性能分析優(yōu)化,程序停止響應的調(diào)試,F(xiàn)irst chance異常捕獲等,還可以監(jiān)視內(nèi)存使用、結合系統(tǒng)性能計數(shù)器使用。
常用用法:
在命令提示符下procdump -?可以查看全部參數(shù)的說明,這里列舉幾個常用的:
-c/-cl: 監(jiān)視CPU占用率閥值,-c為當CPU占用率高于該值時創(chuàng)建dump,-cl則在低于該值時創(chuàng)建dump。
-u: 監(jiān)視單核心的CPU占用率,與-c一起使用
-s: 時間,以秒為單位,結合-c使用實現(xiàn)當連續(xù)N秒CPU占用高于某值時保存dump。
-n: 設置數(shù)量,保存多個dump后才退出該程序。
-h: 當進程中存在掛起窗口(不響應窗口消息)時創(chuàng)建dump。
-m:內(nèi)存到達多大(MB)時創(chuàng)建dump。
-e:當進程遇到未處理的異常時寫入dump【程序奔潰退出】。-e 1 表示在第一次異常時創(chuàng)建dump。eg:托管程序無法捕獲非托管C/c++的異常
-w:如果指定的進程沒有運行,請等待它啟動。
-ma:使用所有進程內(nèi)存 寫入dump。默認轉儲格式僅包含線程和句柄信息。
最后一個參數(shù)寫 dmp文件的保存路徑
!dumpheap -stat
【!dumpheap參數(shù)和SOS幫助系統(tǒng)的一些一般信息】
報錯1:no export dumpheap found
則執(zhí)行.load sos 繼續(xù)報錯:系統(tǒng)找不到指定的文件
參考:加載擴展DLL:load 需要跟完整路徑:0:000> .load C:WindowsMicrosoft.NETFramework64v4.0.30319SOS.dll
繼續(xù)執(zhí)行 !dumpheap -stat
報錯2:Failed to find runtime DLL (clr.dll),0x80004005
再加載一個其他版本的sos:C:WindowsMicrosoft.NETFramework64v2.0.50727SOS.dll
繼續(xù)報錯:Failed to find runtime DLL (mscorwks.dll),0x80004005
改為加載.netcore 2.1 的sos 【因為.netcore3.1下沒有sos,這就為后續(xù)調(diào)試.netcore3.1的程序時埋了個坑】:.load C:Program FilesdotnetsharedMicrosoft.NETCore.App2.1.28sos
參考:.net core dump分析
!gcroot -all報錯:The version of SOS does not match the version of CLR you are debugging
步驟:!dumpheap-typeSystem.String-min10240
正確輸出了,單擊最下面一個。結果顯示 crl版本 與SOS版本不匹配。。所以要下載一個netcore版本下面的SOS。
可是.nercore3.1里面沒有sos.dll,只有一個rm
打開可以看到,進到Installing SOS on Windows
然后執(zhí)行 .load C:Usershuy.dotnetsossos 就好了。
注意:2和3 綜合起來,下次分析dump時,分別執(zhí)行:
.loadby sos crl
.load C:Usershuy.dotnetsossos
!gcroot 返回 Found 0 unique roots
參考:WinDbg not telling me where my string is rooted
這是因為,WinDbg告訴您的是正確的-這些沒有根,它們是垃圾,但是因為它們在LOH上,它們可能不會很快被清除(如果有的話)。您肯定需要重新考慮如何處理XML,將數(shù)據(jù)流輸入/輸出,而不是預先在內(nèi)存中加載/創(chuàng)建數(shù)據(jù)。
修改代碼為:
public static void TestMemory()
{
List<string> list = new List<string>();
for (int i = 0; i < int.MaxValue; i++)
{
string temp = string.Join(",", Enumerable.Range(0, 10000));
list.Add(temp);
if (i % 30 == 0)
SY.Filer.FileHelper.AppendAllText(temp, "temp.txt");
}
Console.ReadLine();
}
重新生成dump去分析
總結
- 上一篇: 三菱a系列motion软体_三菱M70A
- 下一篇: 沈炜:vivo的黄金时代不在过去 仍在将