WinDbg 命令三部曲:(二)WinDbg SOS 扩展命令手
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> 查询一个对象的所有引用根。 对象的引用根可能存在于如下位置:
在查询引用根时,首先在栈上查询,然后是句柄表,最后是对象终结器中的队列中的可达对象。 注:!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: 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> | 打印托管方法的 IL 代码。在调试 DynamicMethod 时非常有效,但同样适合 non-DynamicMethod。 可以在下列 4 种条件下使用:
|
!DumpRCW |
!DumpRCW <RCW address> 显示 RuntimeCallableWrapper 的信息。 |
!DumpCCW |
!DumpCCW <CCW address or COM IP> 显示 COMCallableWrapper 的信息。 |
代码堆栈审查命令 | |
命令 | 描述 |
!Threads |
!Threads [-live] [-special] 列出进程中所有的托管线程。 -live 可选项。仅显示活跃的线程。 -special 可选项。显示由 CLR 创建的特殊线程,这些线程有可能不是托管线程。 例如 GC 线程、调试器线程、终结器线程、应用程序域卸载线程、线程池计时器线程等。 ID 列涵义:
|
!ThreadState |
!ThreadState value 显示线程状态 可能的线程状态包括:
|
!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 尝试仅显示可能感兴趣的线程,包括:
|
!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 句柄类型的过滤。 可用的句柄类型包括:
|
!GCHandleLeaks |
!GCHandleLeaks 帮助检测 GCHandle 泄漏的工具。 |
!FindAppDomain |
!FindAppDomain <Object address> 尝试根据对象查找出 AppDomain。 |
!SaveModule |
!SaveModule <Base address> <Filename> 将内存镜像保存至文件。 |
!ProcInfo |
!ProcInfo [-env] [-time] [-mem] 列出进程中的环境变量,内核 CPU 时间,内存使用率等。 |
!StopOnException (soe) |
!StopOnException [-derived] !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 定义:
|
!VMMap |
!VMMap 遍历虚拟地址空间,列出 Region Protection 类型。 |
!VMStat |
!VMStat 提供虚拟地址空间的综合报告。 |
!MinidumpMode |
!MinidumpMode <0 or 1> 通过 ".dump /m" 或 ".dump" 来获得 CLR 数据的子集,仅适合使用 SOS 的命令的子集,一些 SOS 命令可能失败。 默认值为 0。 |
!AnalyzeOOM (ao) |
!AnalyzeOOM 显示最后一个 OOM 的信息。 |