文章出處

本文為 Dennis Gao 原創技術文章,發表于博客園博客,未經作者本人允許禁止任何形式的轉載。

系列博文

  1. 《WinDbg 命令三部曲:(一)WinDbg 命令手冊》
  2. 《WinDbg 命令三部曲:(二)WinDbg SOS 擴展命令手冊》
  3. 《WinDbg 命令三部曲:(三)WinDbg SOSEX 擴展命令手冊》

導航目錄

SOS 調試命令手冊

擴展加載命令
命令 描述
.loadby

.loadby sos clr 

.load

.load C:\Windows\Microsoft.NET\Framework64\v4.0.30319\sos.dll

對象審查命令
命令 描述

!DumpObj (do)

!DumpObj               顯示指定地址的對象的信息。

!DumpObj -nofields 在顯示結果中不顯示字段信息,這對類似 String 類型等非常有用

!DumpArray (da)

!DumpArray                 檢查數組對象元素

!DumpArray -start        可選項,只支持一維數組,從指定索引處開始顯示數組元素

!DumpArray -length      可選項,只支持一維數組,指定顯示元素的數量

!DumpArray -details      可選項,通過使用 !DumpObj 和 !DumpVC 來打印更多詳細信息

!DumpArray -nofields    可選項,僅在 -details 選項使用時有效,不顯示對象的字段信息

!DumpStackObjects (dso)

!DumpStackObjects            顯示當前調用棧上的所有托管對象的信息,可配合 k 或 CLRStack 命令使用

!DumpStackObjects -verify  將對非靜態類中的所有字段進行檢查

!DumpHeap

!DumpHeap 將遍歷 GC 堆對對象進行分析。通過指定不同的選項,可以查看特定的類型、數組和鎖。

                  如果不加任何選項,該命令的輸出首先為堆中對象的列表,然后是包含已發現類型的列表、大小和數量的報表。

其中 “Free” 對象代表的是垃圾回收器可以使用的區域。如果此區域的大小超過30%則可能意味著出現了堆碎片。

這通常是由于某些對象被持有了較長時間,并且結合了大量高頻率的內存分配。

!DumpHeap 會針對此情況提供一個關于堆碎片化的警告。

-stat              限定輸出為類型統計分析的匯總

-strings          限定輸出為字符串類型的統計分析匯總

-short            限定輸出僅為對象的地址,這將為串行化命令調試帶來便利

-min <size>    忽略尺寸小于給定的 bytes 值的對象

-max <size>   忽略尺寸大于給定的 bytes 值的對象

-live               僅輸出仍然存活的對象

-dead             僅輸出已死亡的對象 (這些對象將在下一個 Full GC 中被回收)

-thinlock         ThinLocks 的報告 (參考 !SyncBlk)

-startAtLowerBound              強制堆指向可使用的地址的低地址邊界

-mt <MethodTable address>  僅列出包含 MethodTable 的對象

-type <partial type name>     僅列出對象類型字符串中包含給定子字符串的對象

start               從給定地址處開始列出對象

end                 從給定地址處停止檢索

start/end 的參數可以通過 !EEHeap -gc 命令來獲取。例如,下面的圖中顯示列出大對象堆中的對象。

!DumpVC

!DumpVC <MethodTable address> <Address>  

檢查值類型對象的字段,在 C# 中指的是 struct,存活于棧中或者被裝箱為 Object 后存放在 GC 堆中。

需要為 SOS 提供值對象的方法表地址,因為值對象與一級對象不同,一級對象的第一個字段即為方法表。

!GCRoot

!GCRoot [-nostacks] <Object address>  查詢一個對象的所有引用根。

對象的引用根可能存在于如下位置:

  1. 棧上
  2. 包含在 GC 句柄中
  3. 準備被終結的對象中
  4. 在上述三點中的對象的成員中

在查詢引用根時,首先在棧上查詢,然后是句柄表,最后是對象終結器中的隊列中的可達對象。

注:!GCRoot 不會棧上的對象根進行有效性校驗。可以使用 !CLRStack 或 !U 來檢查對象是否仍在被使用。

-nostacks   限定僅在句柄表和終結器隊列中查找。

!ObjSize

!ObjSize [<Object address>]  

如果不加參數,!ObjSize 將列出托管線程中所有對象的尺寸。

同時,也會列出進程中的所有 GC 句柄,和句柄指向對象的大小。

在計算對象的尺寸時,!ObjSize 將計算對象及其所有子對象的大小。

!FinalizeQueue

!FinalizeQueue [-detail] | [-allReady] [-short]

!FinalizeQueue   列出所有注冊為終結化的對象。

GC 堆是按照代來劃分,此處同樣列出每代中將被終結的對象的數量。

上圖中顯示了只有 0 代堆中包含了注冊終結對象。"(0015bc90->0015bca0)" 提示了對象指針的內存查詢區域。

-allReady   指定此選項后,將列出所有準備終結化的對象,無論其是否被標注為在當前輪 GC 還是下一輪 GC。

                那些已經不在 "Ready for finalization" 列表中的對象則已經失去了引用根。

                這個選項可能會有些開銷,因為其會驗證是否終結化隊列中的對象是否仍然存在引用根。

-short       限定輸出僅為對象的地址。

                如果與 -allReady 選項同時使用,則將列出所有存在終結器中并且不再是引用根的對象。

                如果單獨使用,則將列出 "Ready for finalization" 隊列中的所有對象。

-detail       顯示額外的信息,例如需要被終結器清理的緩存的數據結構等。

!PrintException (pe)

!PrintException [-nested] [-lines] [<Exception object address>]

!PrintException 將對任意 System.Exception 的衍生對象的字段進行格式化。

                       例如,將對 _stackTrace 字段進行格式化。

                       如果不加任何參數,!PrintException 將查找當前線程上最有一個出現的異常。

                       這與使用 !Threads 中顯示的異常是相同的。

-nested 顯示嵌套的異常信息。

-lines    顯示異常的可用的源信息。

!TraverseHeap

!TraverseHeap [-xml] [-verify] <filename>

!TraverseHeap  將以一種 CLR Profiler 可理解的格式將 GC 堆信息輸出到文件。

可以在如下鏈接下載 CLR Profiler:

http://www.microsoft.com/downloads/details.aspx?FamilyId=86CE6052-D7F4-4AEB-9B7A-94635BEEBDDA&displaylang=en

CLR Profiler 將以圖形化的方式來幫助分析應用程序 GC 堆的狀態。

-verify  將進行更多合法性檢測,可在有任何疑似堆腐化時使用。

-xml     輸出格式指定為 XML 格式。

數據結構審查命令
命令 描述

!DumpDomain

!DumpDomain [<Domain address>]

在無參數時,!DumpDomain 將列出進程中所有的 AppDomain 。同時也會遍歷所有已加載的程序集。

在應用程序的的 AppDomain 之外,還存在另外兩個特殊的應用程序域:Shared Domain 和 System Domain。

所列出的任意程序集的指針均可用于 !DumpAssembly 命令。任何 AppDomain 指針均可被使用于 !DumpDomain 命令。

!EEHeap

!EEHeap [-gc] [-loader]  遍歷進程內存中的 CLR 數據結構。

!EEHeap -gc

!EEHeap -loader

!Name2EE

!Name2EE <module name> <type or method name>

!Name2EE <module name>!<type or method name>

!Name2EE 用于將給定的類名稱轉換為 MethodTable 或 EEClass 的地址。或將方法名稱轉換為 MethodDesc。

!SyncBlk

!SyncBlk [-all | <syncblk number>]

SyncBlock 負責持有一些不是為每個對象都需創建的額外信息,例如 COM Interop 數據、HashCodes、鎖信息等。

例如,假設有如下代碼:

lock (MyObject)
{
  ...  
}

則將設置 MyObject 為當前線程所擁有。一個 SyncBlock 將會為 MyObject 創建,并且包含線程的宿主信息等。

如果另外一個線程試圖執行同樣的代碼,該線程將不能進入該 Block 中直到上一個線程退出。

這將使 !SyncBlk 在檢測托管線程死鎖時非常有用途。例如有如下代碼情形:

Resource r1 = new Resource();
Resource r2 = new Resource();

lock (r1)
{
  lock (r2)
  {
    ...
  }
}

lock (r2)
{
  lock (r1)
  {
    ...
  }
}

通過上面的描述可以了解到,線程 e04 持有著對象 00a7a194,而線程 ab8 持有著對象 00a7a1a4。

再結合調用棧信息可發現死鎖。

此處,可通過運行 !U 或 !DumpHeap -ThinLock 獲取更多信息。

!DumpMT

!DumpMT [-MD] <MethodTable address>  顯示方法表。每個托管對象都在其起始位置包含一個方法表指針。

-MD 顯示對象中定義的方法列表。

!DumpClass

!DumpClass <EEClass address> 顯示 EEClass 中定義的屬性和字段類型。

EEClass 是一種描述對象類型的數據結構。

!Token2EE

!Token2EE <module name> <token>  將 Token 元數據轉換為 MethodTable 或 MethodDesc。

!EEVersion

顯示 CLR 版本。同時也顯示應用程序代碼是運行在 "Workstation" 或 "Server" 模式。

類似的功能可以通過命令:"lm v m clr"

!DumpModule

!DumpModule [-mt] <Module address>  通過模塊地址獲取模塊信息。

-mt 顯示模塊內定義的類型信息。

!ThreadPool

顯示線程池的基本信息,包括隊列中請求的數量、完成端口線程的數量和計時器的數量。

!DumpAssembly

!DumpAssembly <Assembly address> 顯示指定地址程序集的信息。

!DumpSigElem

!DumpSigElem <sigaddr> <moduleaddr>  顯示簽名對象中的一個指定元素信息。

!DumpRuntimeTypes

!DumpRuntimeTypes  從 GC 堆中尋找 System.RuntimeType 類型的對象,并且打印類型名稱和方法表。

!DumpSig

!DumpSig <sigaddr> <moduleaddr>  顯示給定地址的方法或字段的簽名信息。

!RCWCleanupList

!RCWCleanupList [address]  顯示在下一次清理周期內回收的 COM 對象信息。

RuntimeCallableWrapper 是 CLR 內部的數據結構,用于宿主 COM 對象。

通過 System.__ComObject 類向托管代碼暴露。

當相應的對象被 GC 回收之后,相關的 COM 對象引用也不在需要,所以相應的 RCW 也需要被清理。

!DumpIL

!DumpIL <Managed DynamicMethod object> |
              <DynamicMethodDesc pointer> |
              <MethodDesc pointer> |
               /i <IL pointer>

打印托管方法的 IL 代碼。在調試 DynamicMethod 時非常有效,但同樣適合 non-DynamicMethod。

可以在下列 4 種條件下使用:

  1. 如果使用了 System.Reflection.Emit.DynamicMethod 對象,則可將指針作為第一個參數。
  2. 如果使用了 DynamicMethodDesc 指針,可以打印相關動態方法的 IL 代碼。
  3. 如果使用了常規的 MethodDesc,可以將其作為第一個參數來查看 IL 代碼。
  4. 如果有直接的 IL 指針,則可使用 /i 選項和 IL 地址作為參數。

!DumpRCW

!DumpRCW <RCW address>                 顯示 RuntimeCallableWrapper 的信息。

!DumpCCW

!DumpCCW <CCW address or COM IP>  顯示 COMCallableWrapper 的信息。
代碼堆棧審查命令
命令 描述

!Threads

!Threads [-live] [-special]  列出進程中所有的托管線程。

-live        可選項。僅顯示活躍的線程。

-special   可選項。顯示由 CLR 創建的特殊線程,這些線程有可能不是托管線程。

              例如 GC 線程、調試器線程、終結器線程、應用程序域卸載線程、線程池計時器線程等。

ID 列涵義:

  1. 調試器用 ID
  2. CLR 線程 ID
  3. OS 線程 ID

!ThreadState

!ThreadState value   顯示線程狀態

可能的線程狀態包括:

  • Thread Abort Requested
  • GC Suspend Pending
  • User Suspend Pending
  • Debug Suspend Pending
  • GC On Transitions
  • Legal to Join
  • Yield Requested
  • Hijacked by the GC
  • Blocking GC for Stack Overflow
  • Background
  • Unstarted
  • Dead
  • CLR Owns
  • CoInitialized
  • In Single Threaded Apartment
  • In Multi Threaded Apartment
  • Reported Dead
  • Fully initialized
  • Task Reset
  • Sync Suspended
  • Debug Will Sync
  • Stack Crawl Needed
  • Suspend Unstarted
  • Aborted
  • Thread Pool Worker Thread
  • Interruptible
  • Interrupted
  • Completion Port Thread
  • Abort Initiated
  • Finalized
  • Failed to Start

!IP2MD

!IP2MD <Code address>  根據給定的托管 JITTED 代碼,查找相關的 MethodDesc。

上面的例子中,我們通過 Mainy.Main 的返回地址來尋找相關的方法信息。

!U

!U [-gcinfo] [-ehinfo] [-n] <MethodDesc address> | <Code address>

根據給定方法的 MethodDesc 指針,輸出反匯編代碼。

-gcinfo  同時獲得方法的 GCInfo 信息。相關信息可通過 !GCInfo 獲得。

-ehinfo  同時獲得方法的異常信息。相關信息可通過 !EHInfo 獲得。

-n         不顯示行號和符號等信息。

!DumpStack

!DumpStack [-EE] [-n] [top stack [bottom stack]]   提供詳細甚至過于冗余混淆的調用棧信息。

-EE  僅顯示托管函數。

-n    不顯示行號或符號信息。

!EEStack

!EEStack [-short] [-EE]  這個命令用于在進程內的所有線程上運行 !DumpStack。

-EE      該選項將直接被傳遞給 !DumpStack 命令。

-short  嘗試僅顯示可能感興趣的線程,包括:

  1. 線程獲取了一個鎖
  2. 線程為 "jijacked" 狀態,并允許被 GC 回收
  3. 線程當前運行至托管代碼

!CLRStack

!CLRStack [-a] [-l] [-p] [-n]

!CLRStack [-a] [-l] [-p] [-i] [variable name] [frame]

!CLRStack 試圖僅為托管代碼提供真實的調用棧信息。

-p    顯示托管函數的參數信息。

-l     顯示幀內局部變量的信息。

-a    = -p + -l 的組合。

-n    不顯示行信息和符號信息。

!GCInfo

!GCInfo (<MethodDesc address> | <Code address>) 用于診斷 JIT 編譯器是否存在Bug。

!EHInfo

!EHInfo (<MethodDesc address> | <Code address>)  用于顯示 JITTED 方法的異常處理部分。

!BPMD

!BPMD [-nofuturemodule] <module name> <method name> [<il offset>]

!BPMD <source file name>:<line number>

!BPMD -md <MethodDesc>

!BPMD -list

!BPMD -clear <pending breakpoint number>

!BPMD -clearall

!BPMD 用于提供托管代碼的斷點支持。

!COMState

顯示進程的 COM Apartment Model。
垃圾回收歷史審查命令
命令 描述

!HistInit

!HistInit 在運行任何 Hist 族命令之前,需要先根據被調試程序的壓縮日志中初始化 SOS 結構。

!HistRoot

!HistRoot <root>  顯示 promotion 和 relocation 信息。

!HistObj

!HistObj <obj_address>  從日志中檢查 GC relocation 鏈。

!HistObjFind

!HistObjFind <obj_address>  從日志中檢索與對象的 relocation 相關的所有信息。

!HistClear

!HistClear  釋放用于 Hist 族命令的所有資源。通常無需顯式的調用此命令,因為每次 HistInit 會首先清理資源。

診斷工具命令
命令 描述

!VerifyHeap

!VerifyHeap 是一個用于檢測 GC 堆中是否有腐化跡象的診斷工具。

其以如下的模式逐個的走查對象:

!VerifyObj

!VerifyObj <object address> 是一個用于檢查被傳遞的對象參數是否存在腐化的跡象的診斷工具。

!FindRoots

!FindRoots -gen <N> | -gen any | <object address> 用于查找對象的引用根的診斷工具。

!HeapStat

!HeapStat [-inclUnrooted | -iu]  顯示GC堆中每個代的大小和總和,同時顯示空閑空間的大小。

-inclUnrooted  報告中包含那些在 GC 堆中已標識為不再引用的托管對象。

!GCWhere

!GCWhere <object address>  顯示指定對象在 GC 堆中的位置。

!ListNearObj (lno)

!ListNearObj <object address>  用于顯示對象前后的對象的診斷工具。

!GCHandles

!GCHandles [-type handletype] [-stat] [-perdomain]  提供對進程中 GCHandles 的統計分析。

-stat            僅顯示統計信息,而不列出句柄和其指向的信息。

-perdomain   根據 AppDomain 來顯示統計信息。

-type            句柄類型的過濾。

可用的句柄類型包括:

  • Pinned
  • RefCounted
  • WeakShort
  • WeakLong
  • Strong
  • Variable
  • AsyncPinned

!GCHandleLeaks

!GCHandleLeaks  幫助檢測 GCHandle 泄漏的工具。

!FindAppDomain

!FindAppDomain <Object address>  嘗試根據對象查找出 AppDomain。

!SaveModule

!SaveModule <Base address> <Filename>  將內存鏡像保存至文件。

!ProcInfo

!ProcInfo [-env] [-time] [-mem]  列出進程中的環境變量,內核 CPU 時間,內存使用率等。

!StopOnException (soe)

!StopOnException [-derived]
                           [-create | -create2]
                           <Exception>
                           [<Pseudo-register number>]

!StopOnException 當需要調試器在遇到特定的托管異常時停止。

例如,當遇到 System.OutOfMemoryException 時停止,而遇到其他異常時繼續運行。

!DumpLog

!DumpLog [-addr <addressOfStressLog>] [<Filename>]  允許將 CLR in-memory stress log 日志寫入文件。

通過下面注冊表內的信息更改 Stress Log 設置:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework:

(DWORD) StressLog = 1

(DWORD) LogFacility = 0xffffffbf 

(DWORD) StressLogSize = 65536

(DWORD) LogLevel = 6

LogFacility 定義:

  • GC            0x00000001
  • GCINFO         0x00000002
  • STUBS          0x00000004
  • JIT                0x00000008
  • LOADER        0x00000010
  • METADATA     0x00000020
  • SYNC            0x00000040
  • EEMEM          0x00000080
  • GCALLOC      0x00000100
  • CORDB         0x00000200
  • CLASSLOADER 0x00000400
  • CORPROF       0x00000800
  • REMOTING      0x00001000
  • DBGALLOC     0x00002000
  • EH                 0x00004000
  • ENC               0x00008000
  • ASSERT         0x00010000
  • VERIFIER        0x00020000
  • THREADPOOL  0x00040000
  • GCROOTS       0x00080000
  • INTEROP         0x00100000
  • MARSHALER    0x00200000
  • IJW                0x00400000
  • ZAP                0x00800000
  • STARTUP         0x01000000
  • APPDOMAIN     0x02000000
  • CODESHARING 0x04000000
  • STORE             0x08000000
  • SECURITY        0x10000000
  • LOCKS             0x20000000
  • BCL                 0x40000000

!VMMap

!VMMap  遍歷虛擬地址空間,列出 Region Protection 類型。

!VMStat

!VMStat  提供虛擬地址空間的綜合報告。

!MinidumpMode

!MinidumpMode <0 or 1>

通過 ".dump /m" 或 ".dump" 來獲得 CLR 數據的子集,僅適合使用 SOS 的命令的子集,一些 SOS 命令可能失敗。

默認值為 0。

!AnalyzeOOM (ao)

!AnalyzeOOM 顯示最后一個 OOM 的信息。

參考資料

本文為 Dennis Gao 原創技術文章,發表于博客園博客,未經作者本人允許禁止任何形式的轉載。

系列博文

  1. 《WinDbg 命令三部曲:(一)WinDbg 命令手冊》
  2. 《WinDbg 命令三部曲:(二)WinDbg SOS 擴展命令手冊》
  3. 《WinDbg 命令三部曲:(三)WinDbg SOSEX 擴展命令手冊》

 


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()