zoukankan      html  css  js  c++  java
  • WinDbg 命令三部曲:(二)WinDbg SOS 扩展命令手册

    本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载。

    系列博文

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

    导航目录

    SOS 调试命令手册

    扩展加载命令
    命令 描述
    .loadby

    .loadby sos clr 

    .load

    .load C:WindowsMicrosoft.NETFramework64v4.0.30319sos.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_MACHINESOFTWAREMicrosoft.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 扩展命令手册》
  • 相关阅读:
    步步为营 C# 技术漫谈 一、反射机制
    Windows API、CRT和STL
    MVC3 基本业务开发框架
    .NET实现之(WebBrowser数据采集—终结篇)
    步步为营 C# 技术漫谈 二、ASP.NET 页生命周期
    步步为营 .NET 代码重构学习笔记 十
    步步为营 .NET 代码重构学习笔记 十三
    MagicDict开发总结6 [划词 检索]
    步步为营 .NET 代码重构学习笔记系列总结
    项目多少是可以配置的?
  • 原文地址:https://www.cnblogs.com/gaochundong/p/windbg_sos_cheat_sheet.html
Copyright © 2011-2022 走看看