1. 解決線上.NET應用程式的如下問題:
- 崩潰
- CPU高
- 程式異常
- 程式Hang死
2. 安裝WinDbg:
http://msdn.microsoft.com/en-us/windows/hardware/gg463009.aspx
3. 配置WinDbg:
運作WinDbg->菜單->File->Symbol File Path->按照下面的方法設定_NT_SYMBOL_PATH變量:
在彈出的框中輸入“C:\MyCodesSymbols; SRV*C:\MyLocalSymbols*http://msdl.microsoft.com/download/symbols”(按照這樣設定,WinDbg将先從本地檔案夾C:\MyCodesSymbols中查找Symbol,如果找不到,則自動從MS的Symbol Server上下載下傳Symbols)。另一種做法是從這個Symbol下載下傳位址中http://www.microsoft.com/whdc/devtools/debugging/symbolpkg.mspx,下載下傳相應作業系統所需要的完整的Symbol安裝包,并進行安裝,
4. 利用WinDbg裡的adplus來擷取dump檔案。
Dump檔案是程序的記憶體鏡像。可以把程式的執行狀态通過調試器儲存到dump檔案中。
在WinDbg安裝目錄裡可以找到adplus.exe,把他拖入到指令行中,然後用指令
adplus.exe -hang -pn test.exe -o c:\dumps // 抓取目前的dump檔案
adplus.exe -crash -pn test.exe -o c:\dumps // 監聽應用程式,當crash時,擷取dump檔案
指令-pn :應用程式名,-p:應用程式pid,-odump檔案輸出路徑
5. 利用WinDbg加載dump檔案加載調試器
運作WinDbg->菜單->File->Open Cresh dump 打開dump檔案,并加載.net調試器
.loadby sos mscorwks .Net 3.5版本及以下
.loadby sos clr .Net 4.0
如果伺服器的.Net版本與本機不比對需要伺服器版本的mscordacwks.dll檔案
并設定.sympath = mscordacwks_x86_x86_2.0.50727.3607.dl
6. WinDbg的基本指令
help sos指令幫助
!threads 顯示所有線程
!dumpheap 顯示托管堆的資訊
!clrstack 顯示調用棧
!dumpobj 顯示一個對象的内容
!dumparray 顯示數組
!syncblk 顯示同步塊
!runaway 顯示線程cpu時間
!gcroot 跟蹤對象記憶體引用
!pe 列印異常
7. WinDbg的使用
當我在Form中執行這段代碼:
public Form1(){
InitializeComponent();
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
}
private void UnhandledExceptionProc(object obj){
try {
throw new Exception("1st chance");
} catch (Exception) {
MessageBox.Show("after 1st");
}
int d = 0;
int n = 1 / d;
}
并活動dump檔案
用windbg打開dump檔案後輸入-pe:可以看到問題的所在。
異常如此重要,是以作業系統提供了對應的調試功能,可以使用調試器來檢視異常。異常發生後,作業系統在調用使用者态程式的異常處理函數前,會檢查目前使用者态程式是否有調試器加載。如果有,那麼作業系統會首先把異常資訊發送給調試器,讓調試器有觀察異常的第一次機會,是以也叫做first chance exception,調試器處理完畢後,作業系統才讓使用者态程式來處理。 如果使用者态程式處理了這個異常,就沒調試器什麼事了。否則,程式在unhandled exception崩潰前,作業系統會給調試器第二次觀察異常的機會,是以也叫做second chance exception。
《Windows使用者态程式高效排錯》
分析以下代碼:可以看出DummyObject 會占用很多記憶體,甚至導緻記憶體溢出
private void MemeryLeakProc(object obj)
{
while (true) {
for (int i = 0; i < 100 * 1024; i++) {
DummyObject o = new DummyObject();
list.Add(o);
}
Thread.Sleep(1000);
}
}
windbg指令:!dumpheap –stat 統計堆棧記憶體
線程Hang住的常見原因
-線程池或工作線程集中在某個耗時的工作當中,或者被其他線程鎖住
核心問題,找到被hang住的線程
!threads
~*e!clrstack
!synblk
lock (syncRoot) {
int tp;
int io;
//ThreadPool.GetMaxThreads(out tp, out io);
for (int i = 0; i < 100; i++) {
Thread hangThread = new Thread(HangProc);
hangThread.Start();
}
MessageBox.Show("Press to release lock");
}
private void HangProc(object obj)
{
lock (syncRoot) {
n = 0;
}
}
CPU高
-如果與業務量沒有提升,有線程在長時間的處理
核心問題,找到占用CPU的線程
!runaway
~*e!clrstack
線程死鎖出現的情況:
兩個鎖A,B,
一個線程已經拿到鎖A,申請鎖B,
另一個線程已經拿到鎖B,申請鎖A
核心問題:找到鎖定的線程
!threads
!syncblk
~*e!clrstack
•兩條指令可以解決大部分的問題 •!dumpheap –stat •~*e!clrstack