SOS扩展命令

一、SOS扩展命令

  SOS包含几十个命令,要熟练使用SOS,首先要了解SOS有哪些命令。下面给出SOS命令列表。

命令描述
BPMD [<module name> <method name>] [-md <MethodDesc>]建立一个断点在指定模块的指定方法上。如果指定模块和方法尚未被载入,该命令等到该模块被载入并且被即时(just-in-time)编译的通知后再建立断点。
CLRStack [-a] [-l] [-p]只提供托管代码的栈跟踪。-p 选项显示托管函数的参数。-l 选项显示在一个框架里局部变量的信息。SOS调试扩展无法检索局部变量的名字,所以局部变量的输出格式为<local address> = <value>。-a (all) 选项是-l-p组合的快捷方式。在x64和基于IA-64的平台上,SOS调试扩展不显示过渡框架(Transition Frames)。
COMState列出每个线程COM单元模型和可用的上下文指针。
DumpArray [-start <startIndex>] [-length <length>] [-details] [-nofields] <array object address>-或者-DA [-start <startIndex>] [-length<length>] [-detail] [-nofields] <array object address>检查一个数组对象的元素。-start 选项指定显示元素的起始索引号。-length 选项指定要显示的元素数目。-detail 选项按照DumpObjDumpVC格式显示元素的细节。-nofields 选项使数组显示不包括字段。仅当指定 -detail 选项时该选项才可用。
DumpAssembly <Assembly address>显示一个汇编集的有关信息。如果存在多个模块,DumpAssembly命令将它们全部列出。你可以用DumpDomain命令得到汇编集地址。
DumpClass <EEClass address>显示与一个类型相关的EEClass结构这些信息。DumpClass命令显示静态字段值而不显示非静态字段值。使用DumpMTDumpObjName2EE、或Token2EE命令来获取一个EEClass结构地址。
DumpDomain [<Domain address>]枚举在指定AppDomain对象地址里面装载的每一个Assembly对象。当不带参数调用DumpDomain命令时,它列出一个进程中所有的AppDomain对象。
DumpHeap [-stat] [-min <size>][-max <size>] [-thinlock] [-mt<MethodTable address>] [-type<partial type name>][start [end]]显示关于垃圾收集堆的信息和有关对象的收集统计。DumpHeap命令如果在垃圾收集器堆中检测到过多的碎片,它显示一个警告。-stat 选项限制输出内容只有统计的类型摘要。-min 选项忽略那些尺寸小于size参数的对象,以字节为单位。-max 选项忽略那些尺寸大于size参数的对象,以字节为单位。-thinlock 选项报告ThinLocks。更多信息请看SyncBlk命令。-mt 选项只列出符合所指定MethodTable结构的那些对象。-type 选项只列出类型名字子串匹配指定字符串的那些对象。参数 start 指定开始列出的地址。参数 end 指定停止列出的地址。
DumpIL [<DynamicMethod address>] [<DynamicMethodDesc address>] [<MethodDesc address>]显示与一个托管方法相关的中间语言(IL)。注意,动态IL是发射来的(emitted),不同于从一个汇编集装载的IL。动态IL引用一个托管对象数组中的对象,而不是通过元数据标记引用对象。
DumpLog [<Filename>]把一个内存里的重要日志的内容写入指定文件。如果你没有指定文件名,该命令在当前目录中创建一个名为Stresslog.txt的文件。公共语言运行时提供一个内存里的重要日志,帮助你诊断重要失败。日志使你可以不使用锁或I/O就能诊断失败。若要启用重要日志,需要在HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/.NETFramework下面设置以下注册表项:(DWORD) StressLog = 1(DWORD) LogFacility = 0xffffffff(DWORD) StressLogSize = 65536
DumpMD <MethodDesc address>显示的信息是在指定地址上的一个MethodDesc结构。你可以用IP2MD命令得到一个托管函数的MethodDesc结构地址。
DumpMT [-MD] <MethodTable address>显示在指定地址上的一个方法表的有关信息。指定 -MD 选项显示列出该对象定义的所有方法。每个托管对象包含有一个方法表指针。
DumpMethodSig <sigaddr> <moduleaddr>显示在指定地址上的一个MethodSig结构的有关信息。
DumpModule [-mt] <Module address>显示在指定地址上的一个模块的有关信息。-mt 选项显示在该模块中所定义的类型和被该模块引用的类型。你可以用DumpDomainDumpAssembly命令检索一个模块的地址。
DumpObj <object address>-或者-DO <object address>显示在指定地址上的一个对象的有关信息。DumpObj命令显示字段、EEClass结构信息、方法表和该对象的尺寸。你可以用DumpStackObjects命令检索一个对象的地址。注意,因为类型CLASS的字段也是对象,所以你可以对它们执行DumpObj命令。
DumpRuntimeTypes显示在垃圾收集器堆中的运行时类型对象,并列出与它们相关的类型名字和方法表。
DumpStack [-EE] [top stack [bottom stack]]显示一个栈跟踪(回溯)。-EE 选项使DumpStack命令只显示托管函数。在x86平台上使用topbottom参数限制所显示的栈框架。在x86平台上,DumpStack命令创建一个冗长的栈跟踪。在x64和基于IA-64的平台上,DumpStack命令模仿调试器的 K 命令。在x64和基于IA-64的平台上topbottom参数被忽略。
DumpSig <sigaddr> <moduleaddr>显示在指定地址上的一个Sig结构的有关信息。
DumpStackObjects [-verify] [top stack [bottom stack]]-或者-DSO [-verify] [top stack [bottom stack]]显示在当前栈范围内找到的所有托管对象。-verify 选项验证对象字段的每一个非静态CLASS字段。带有栈跟踪命令使用DumpStackObject命令,比如 K 命令和CLRStack命令确定局部变量和参数的值。
DumpVC <MethodTable address> <Address>显示在指定地址上的一个值类的字段信息。MethodTable参数使DumpVC命令能够正确地解释字段。值类不以方法表作为它们的第一个字段。
EEHeap [-gc] [-loader]显示被公共语言运行时内部数据结构使用的进程内存的有关信息。-gc 和 -loader 选项限制该命令的输出内容为垃圾收集器或者装载器的数据结构。对于垃圾收集器,列出在托管堆里每一个节的范围信息。如果某指针是在EEHeap -gc给出的某个节范围内,那么该指针是一个对象指针。
EEStack [-short] [-EE]对进程中所有线程执行DumpStack命令。-EE 选项被直接传递给DumpStack命令。-short 参数限制输入内容为以下线程种类:已经被锁定的线程。为了允许垃圾收集已经被迟延的线程。目前处于托管代码中的线程。
EEVersion显示公共语言运行时版本。
EHInfo [<MethodDesc address>] [<Code address>] 显示所指定方法里的异常处理块。这个命令显示子句块(try块)和处理者块(catch块)的代码地址及偏移量。
FinalizeQueue [-detail]显示为终结(finalization)而登记的所有对象。-detail 选项显示关于等待清除的任何SyncBlocks的附加信息和等待清除的任何RuntimeCallableWrappers (RCWs) 的额外信息。两个数据结构都是由终结器(finalizer)线程缓存和清除。
FindAppDomain <Object address>确定在指定地址上的一个对象的应用程序域。
GCHandles [-perdomain]显示在进程中垃圾收集器句柄的统计。如果传递-perdomain 选项,则按照应用程序域顺序排列统计。使用GCHandles命令查找由垃圾收集器句柄泄漏引起的内存泄漏。例如,由于一个强健的垃圾收集器句柄指向代码的一个大数组成部分,而该句柄没有被释放就丢弃了,所以代码实际上还保留着这个数组,这时就出现一个内存泄漏。
GCHandleLeaks在内存里搜索进程中对那些强健而且有麻烦的垃圾收集器句柄的任何引用,并且显示结果。如果找到某个句柄,GCHandleLeaks命令显示该引用的地址。如果在内存里没有找到某个句柄,这个命令显示一个通知。
GCInfo <MethodDesc address><Code address>显示数据指示何时寄存器或栈位置包含有托管对象。如果发生垃圾收集,收集器必须知道指向对象的引用的位置,如此它才可以用新的对象指针值更新它们。
GCRoot [-nostacks] <Object address>显示对在指定地址上的一个对象的引用(或根)信息。GCRoot命令检查整个托管堆和在栈以及其他对象里面句柄的句柄表。然后,在每个栈和终结器队列中搜索指向对象的指针。这个命令不确定一个栈根是有效的还是已丢弃的。为了确定栈根是否还在使用中,需要用CLRStackU命令反汇编局部变量或参数值所属的框架。-nostacks 选项限制只搜索垃圾收集器句柄和终结器队列里的对象(freachable objects)。
help [<command>] [<faq>]当没有指定参数时显示所有可用命令,或者当指定命令为参数时显示其详细帮助信息。faq 参数显示常问问题的答案。
IP2MD <Code address>显示在已经即时编译(JIT)的代码里指定地址上的MethodDesc结构。
MinidumpMode [0] [1防止在使用一个小转储(minidump)时执行非安全命令。传递 0 以禁用这个功能,或传递 1 以启用这个功能。默认地,MinidumpMode把值设置为 0 。用 .dump /m 命令或者 .dump 命令创建的小转储已经限制为特定的CLR数据,并且让你只可以正确地运行SOS命令的一个子集。有些命令可能因不可预见的错误而失败,因为所必需的内存区域没有被映射或者只有部分被映射。这个选项让你避免对小转储执行非安全命令。
Name2EE <module name> <type or method name>-或者-Name2EE <module name>!<type or method name>显示指定模块中指定类型或方法的MethodTable结构和EEClass结构。指定模块必须被装入进程中。可以使用MSIL反汇编器 (Ildasm.exe) 浏览模块,以取得适当的类型名字。你也可以传递 * 作为模块名字参数以搜索所有装入的托管模块。模块名字参数也可以是调试器给一个模块的名字,比如mscorlib或image00400000。这个命令支持Windows调试器句法<module>!<type>。该类型必须被完全限定。
ObjSize [<Object address>]显示指定对象的尺寸。若不带参数,则ObjSize命令显示在托管线程中找到的全部对象的尺寸,显示进程中全部的垃圾收集器句柄,并求出指向那些句柄的所有对象的尺寸总和。ObjSize命令把父对象全部子对象的尺寸也计算在内。
PrintException [-nested] [<Exception object address>]-或者-PE [-nested] [<Exception object address>]编排格式并显示在指定地址上的任何Exception类派生对象的字段。如果你没有指定一个地址,PrintException命令显示当前线程上最近抛出的异常。-nested 选项详细显示嵌套的异常对象。你可以使用这个命令编排格式并查看_stackTrace字段,这是一个二元数组。
ProcInfo [-env] [-time] [-mem]显示针对该进程的环境变量、内核CPU时间和内存使用统计。
RCWCleanupList<RCWCleanupList address>显示在指定地址上的正等待清除的运行时可调用的包裹器列表。
SaveModule <Base address> <Filename>把装入在指定地址上的一个内存映像写入指定文件。
StopOnException [-derived] [-create | -create2] <Exception> <Pseudo-register number>使调试器当指定异常被抛出时停止,而当其他异常被抛出时则继续运行。-derived 选项捕获指定异常及其衍生的每个异常。
SyncBlk [-all | <syncblk number>]显示指定的SyncBlock结构或者所有的SyncBlock结构。如果你没有传递任何参数,SyncBlk命令显示一个线程所有对象相应的SyncBlock结构。一个SyncBlock结构是一个附加信息的容器,不必为每个对象创建它。它能够容纳COM互用数据、散列码、和用于线程-安全操作的锁定信息。
ThreadPool显示托管线程池的有关信息,包括在队列中工作请求的数目、完全端口线程的数目、和计时器数目。
Token2EE <module name> <token>把指定模块中指定的元数据标记转换成一个MethodTable结构或者MethodDesc结构。你也可以把 * 作为模块名字参数,以使在每个被载入的托管模块中找出该标记的映射目标。模块名字参数也可以是调试器给一个模块的名字,比如mscorlib 或 image00400000 。
Threads [-live] [-special]显示进程中所有的托管线程。Threads命令显示 调试器简写ID号、公共语言运行时线程ID号、和正在操作中的系统线程ID号。此外,Threads命令显示 一个Domain栏指示线程运行所处在的应用程序域、一个APT栏显示COM单元的模式、和一个Exception栏显示线程最近抛出的异常。-live 选项显示与某个活线程有关联的那些线程。-special 选项显示CLR创建的所有特别线程。特别线程包括(并发GC和服务器GC中的)垃圾收集(GC)线程、调试器助手线程、Finalizer线程、AppDomain卸载线程、和线程池计时器线程。
TraverseHeap [-xml] <filename>遵照CLR简档器隐含的格式把堆信息写入到指定文件。-xml选项使TraverseHeap命令把该文件格式化为XML。
U [-gcinfo] [-ehinfo] <MethodDesc address> | <Code address>通过指定一个指向某个方法MethodDesc结构的指针或者指定其方法体里面的一个代码地址,显示一个托管方法有注释的反汇编。U命令显示整个方法,从开始到完成,并在注释里把元数据标记转换为名字。-gcinfo 选项使U命令显示这个方法使用的GCInfo结构。-ehinfo 选项显示这个方法的异常信息。你也可以用EHInfo命令来获取该信息。
VerifyHeap检查垃圾收集器堆的崩溃标志,显示发现的任何错误。堆崩溃能够由不正确地构成的平台援用(platform invoke)调用引起。
VMMap横跨虚拟地址空间,显示加诸每区域的保护类型。
VMStat按照加诸内存的保护类型(自由的free、保留的reserved、约束的committed、私有的private、映射的mapped、映像image)顺序,提供虚拟地址空间的概览。TOTAL栏显示AVERAGE栏乘以BLK COUNT栏的结果。

二、加载SOS

  SOS调试扩展让你可以查看在公共语言运行时里面运行的代码的有关信息。例如,你可以使用SOS调试扩展显示托管堆的有关信息,查找堆的错误,显示运行时使用的内部数据类型,以及查看在运行时里面运行的所有托管代码的有关信息。

  在调试托管代码时,有两个扩展DLL需要注意,它们分别是SOS和SOSEX。

  在使用SOS之前,第一步就是要加载SOS。

  1、元命令loadby加载SOS

  元命令loadby尝试找出由ModuleName指定的路径(通过查看进程中的已加载模块列表),并且使用这个路径来加载指定的DLLNAME(调试器扩展的DLL)。

  如果mscorwks模块还没有被加载,那么元命令loadby将提示以下错误信息:

0:000> .loadby sos.dll mscorwks
Unable to find module 'mscorwks'

  在Windbg.exe中装载SOS的命令是:

.loadby sos mscorwks

  2、元命令load加载SOS

  如果使用的.Net版本不同,那么还可以手动指定版本,如手动指定载入4.0版本命令:

.load C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/sos.dll
.load C:/WINDOWS/Microsoft.NET/Framework/v4.0.30319/sos.dll

  如果是64位,那么应该加载如下sos.dll

.load C:/Windows/Microsoft.NET/Framework64/v2.0.50727/sos.dll
.load C:/Windows/Microsoft.NET/Framework64/v2.0.50727/sos.dll

  SOS.dll 随 .NET Framework 安装在 %windir%\microsoft.net\framework\<.NET 版本> 目录下。

  3、加载mscordacwks.dll

  在调试.Net程序时,调试器可以加载一个辅助DLL,称为mscordacwks.dll,这个DLL用于输出托管代码调试过程中的各种信息。加载mscordacwks.dll的路径取决于被加载到进程中的mscorwks.dll的路径。在实时调试中通常不存在问题,因为我们希望加载与已加载的mscorwks.dll相对应的mscordacwks.dll版本,但在事后调试中则可能出现版本不匹配的情况。要想控制调试行为,我们可以使用元命令,cordll,并控诉调试器加载mscordacwks.dll的确切位置。例如,如果要指定一个新路径,那么可以使用以下命令:

.cordll -lp c:\x\y\z

  这样便能告诉调试器从文件夹c:\x\y\z下加载mscordacwks.dll。如果要卸载mscordacwks.dll可以使用-u开关。

三、内存转储

  在调试器中有许多命令都可以用来转储内存的内容。内存转储通常用于查看内存中的对象。最常用的命令是d(表示内存)。命令d的最简单形式只带有一个参数,表示需要显示的内存地址。命令d能够以非常简洁的形式显示需要查看的内存。

  • dd:直接显示内存;
  • du:把被转储的内存视为Unicode字符;
  • da:把被转储的内存视为ASCII字符;
  • dw:把被转储的内存视为字(word);
  • db:把被转储的内存视为字节值和ASCII字符;
  • dq:把被转储的内存视为四字(quad word)值;

  1、DumpObj 转储引用类型

  DumpObj的缩写为dso。要判断一个指针指向的是否是值类型,最佳方式就是使用DumpObj命令,但它只对引用类型有效。DumpObj命令的参数是一个指向引用类型的指针,能输出这个引用类型的内容。如果给定的指针指向一个值类型,那么DumpObj命令会给出以下错误提示:

0:000> !DumpObj 0x002bf0b4
<Note: this object has an invalid CLASS field>
Invalid object

  DumpObj详细介绍:

复制代码
0:083> !do 00000002838d92c8
Name: System.String
MethodTable: 000007fef0667d90
EEClass: 000007fef026e560
Size: 411932(0x6491c) bytes
 (C:\Windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: 粤A87xxx,粤ACxxx挂......
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fef066f000  4000096        8         System.Int32  1 instance           205954 m_arrayLength
000007fef066f000  4000097        c         System.Int32  1 instance           205953 m_stringLength
000007fef06697d8  4000098       10          System.Char  1 instance             7ca4 m_firstChar
000007fef0667d90  4000099       20        System.String  0   shared           static Empty
                                 >> Domain:Value  000000000112bef0:00000001ff350370 000000000372e6e0:00000001ff350370 <<
000007fef0669688  400009a       28        System.Char[]  0   shared           static WhitespaceChars
                                 >> Domain:Value  000000000112bef0:00000001ff350b60 000000000372e6e0:00000001ff3588e8 <<
复制代码
  • Name:对象的类型。如上面是一个字符串。
  • Size:对象的大小。如上面是411932 bytes。
  • String:这个是对字符串类型的特别关照,可以看到内容。其他对象就不知道了。
  • Fields:指向其他类型的引用

  说明:

选项说明
MT这个域的方法列表
Field这个域的元数据。高顺序位(4)表示它是一个域,而低顺序位(1)是在元数据表中的偏移。
Offset这个域在引用类型内存布局中的偏移。
Type这个类型的缩写名字。
VT如果被设置为1,那么表示这是一个值类型,如果为0,这表示是一个引用类型。
Attr对象的属性。
Value域的值。
Name域的名字。

  2、DumpVC 转储值类型

  DumpVC的唯一作用就是显示值类型,它能够转储引用类型里面的值类型。

  它唯一的形式如下:

  !DumpVC <MethodTable address> <Address>

  在DumpObj命令的输出中可以很容易地得到”Method Table Address”和”Address”。Method Table Address就是do命令Fields下的MT列,Address就是Value列。

复制代码
0:083> !DumpVC 907b50 67903084
Not a managed object
0:083> !DumpVC 000007fef066f000 191394 
Name: System.Int32
MethodTable 000007fef066f000
EEClass: 000007fef0272088
Size: 24(0x18) bytes
 (C:\Windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fef066f000  4000411        0         System.Int32  1 instance  m_value
复制代码

   3、!DumpStackObjects 当前线程对象分配过程

  !DumpStackObjects  当前线程的对象分配过程。缩写形式为!dso。

复制代码
0:083> !dso
OS Thread Id: 0x6914 (83)
RSP/REG          Object           Name
000000000b65c470 000000022f3cfe10 System.Web.HttpApplication+PipelineStepManager
000000000b65c8a8 00000002838d92c8 System.String
000000000b65ca10 000000014f620fe0 System.String
000000000b65ca18 00000002838d92c8 System.String
000000000b65ca20 000000014f621260 System.String
000000000b65ca38 000000022f3cfe10 System.Web.HttpApplication+PipelineStepManager
000000000b65ca98 000000022f3cfe10 System.Web.HttpApplication+PipelineStepManager
000000000b65caa0 000000022f3cfe10 System.Web.HttpApplication+PipelineStepManager
000000000b65cab0 00000001dfc47d28 System.String
000000000b65cab8 000000014f621260 System.String
000000000b65cad0 000000014f620fe0 System.String
000000000b65cb00 000000014f620fe0 System.String
000000000b65cb30 000000014f620fe0 System.String
...
复制代码

  4、ObjSize 查看对象大小

  ObjSize 用于知道对象地址时,查看该对象的大小。

0:083> !ObjSize 00000001ff350370
sizeof(00000001ff350370) = 32 ( 0x20) bytes (System.String)

   5、DumpHeap 

  显示关于垃圾收集堆的信息和有关对象的收集统计。

  • -stat 选项限制输出内容只有统计的类型摘要。
  • -min 选项忽略那些尺寸小于size参数的对象,以字节为单位。
  • -max 选项忽略那些尺寸大于size参数的对象,以字节为单位。
  • -thinlock 选项报告ThinLocks。更多信息请看SyncBlk命令。
  • -mt 选项只列出符合所指定MethodTable结构的那些对象。
  • -type 选项只列出类型名字子串匹配指定字符串的那些对象。
  • 参数 start 指定开始列出的地址。
  • 参数 end 指定停止列出的地址。

  !DumpHeap -type People  :统计出含有类名中含有People的对象。

  !DumpHeap -mt 79105cd4  : 根据MT结构查询详细信息。能够根据MT查询到Address以用于!do命令。

复制代码
0:083> !DumpHeap -stat
------------------------------
Heap 0
total 140040 objects
------------------------------
Heap 1
total 108057 objects
------------------------------
...
Heap 23
total 73065 objects
------------------------------
total 2737406 objects
Statistics:
              MT    Count    TotalSize Class Name
000007ff00ff7140        1           24 Comit.TE.Web.Areas.Management.Controllers.PrintProfilesController+PrintProfilesBrief[]
...
000007fef066f000  1170210     28085040 System.Int32
00000000010c12d0      228     32131528      Free
000007fef066f8b0    67392     46915920 System.Collections.Hashtable+bucket[]
000007fef0667d90   291003     96055608 System.String
Total 2737406 objects
Fragmented blocks larger than 0.5 MB:
            Addr     Size      Followed by
000000014f92ff10    4.2MB 000000014fd5c698 System.String
000000019fb89940    6.3MB 00000001a01d57b8 System.Threading.OverlappedData
000000020fb18698    5.7MB 00000002100ccc70 System.Threading.Overlapped
复制代码

  6、DumpArray

  DumpArray用于转储数组。

复制代码
0:000> !DumpArray 00000000ffb44c28
Name: System.Object[]
MethodTable: 000007fef0655b80
EEClass: 000007fef026eb88
Size: 96(0x60) bytes
Array: Rank 1, Number of elements 8, Type CLASS
Element Methodtable: 000007fef0667680
[0] 00000000ff5dc768
[1] 000000014f438e50
[2] 00000000ffb44a50
[3] 000000010f668698
[4] 00000000ffb44c10
[5] 00000000ffb44c88
[6] null
[7] null
复制代码

  [0]、[1]、[2]、[3]…就是值的地址,只要!do这个地址就能够查看了。

  那么!DumpArray后面跟的地址又来自哪里呢?来自于!do命令的第一行Fields的Value:

  !dumpheap -stat -> !dumpheap -mt MT列 -> !do Address列 -> !DumpArray Fields第一行Value列 -> !do[0][1][2] 

复制代码
0:000> !DumpObj 00000000ffb44be8
Name: System.Collections.ArrayList
MethodTable: 000007fef066ec78
EEClass: 000007fef0271f10
Size: 40(0x28) bytes
 (C:\Windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fef0655b80  400094d        8      System.Object[]  0 instance 00000000ffb44c28 _items
000007fef066f000  400094e       18         System.Int32  1 instance                6 _size
000007fef066f000  400094f       1c         System.Int32  1 instance                6 _version
000007fef0667680  4000950       10        System.Object  0 instance 0000000000000000 _syncRoot
000007fef0655b80  4000951      388      System.Object[]  0   shared           static emptyArray
                                 >> Domain:Value  000000000112bef0:00000001ff354350 000000000372e6e0:00000001ff35bc08 <<
复制代码

  7、FinalizeQueue [-detail]

  已进入待终结Finalizer队列的对象。

复制代码
0:083> !FinalizeQueue
SyncBlocks to be cleaned up: 0
MTA Interfaces to be released: 0
STA Interfaces to be released: 0
----------------------------------
------------------------------
Heap 0
generation 0 has 3 finalizable objects (000000002e188cf0->000000002e188d08)
generation 1 has 46 finalizable objects (000000002e188b80->000000002e188cf0)
generation 2 has 4448 finalizable objects (000000002e180080->000000002e188b80)
Ready for finalization 0 objects (000000002e188d08->000000002e188d08)
------------------------------
...
Heap 23
generation 0 has 2963 finalizable objects (00000000329be080->00000000329c3d18)
generation 1 has 0 finalizable objects (00000000329be080->00000000329be080)
generation 2 has 0 finalizable objects (00000000329be080->00000000329be080)
Ready for finalization 0 objects (00000000329c3d18->00000000329c3d18)
Statistics:
              MT    Count    TotalSize Class Name
000007fef0681898        1           24 System.Threading.OverlappedDataCache
...
000007fef0690639     8779       632088 UNKNOWN
000007fef065f2a9    40751      1304032 UNKNOWN
000007fef065f2a8    41408      1325056 System.WeakReference
Total 92039 objects
复制代码

四、线程

  1、ThreadPool 线程池相关信息

  显示托管线程池的有关信息,包括在队列中工作请求的数目、完全端口线程的数目、和计时器数目。

复制代码
0:083> !ThreadPool
CPU utilization 81%
Worker Thread: Total: 24 Running: 21 Idle: 3 MaxLimit: 2147483647 MinLimit: 24
Work Request in Queue: 45
AsyncTimerCallbackCompletion TimerInfo@000000001043dee0
AsyncTimerCallbackCompletion TimerInfo@000000001043dee0
...
AsyncTimerCallbackCompletion TimerInfo@00000000108d4140
AsyncTimerCallbackCompletion TimerInfo@00000000108c9c20
--------------------------------------
Number of Timers: 55
--------------------------------------
Completion Port Thread:Total: 1 Free: 1 MaxFree: 48 CurrentLimit: 0 MaxLimit: 2147483647 MinLimit: 24
复制代码

CPU utilization:占用CPU百分比;

  Worker Thread: 工作线程统计:

  • Total: 工作线程总数;
  • Running:正在运行的工作线程数;
  • Idle:空转线程数;
  • MaxLimit:最大允许运行的线程数;
  • MinLimit:最小允许运行的线程数;
  • Number of Timers:计时器数量;

Completion Port Thread:I/O线程数统计:

  • Total:I/O线程总数;
  • Free:空闲I/O线程数;
  • MaxFree:最大空闲I/O线程数;
  • CurrentLimit: 当前I/O限制数;
  • MaxLimit:最大I/O线程数限制;
  • MinLimit:最小I/O线程数限制;

  2、Threads [-live] [-special]

  显示进程中所有的托管线程。

复制代码
0:083> !Threads -special
ThreadCount: 32
UnstartedThread: 0
BackgroundThread: 32
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
                                              PreEmptive                                                Lock
       ID OSID        ThreadOBJ     State   GC     GC Alloc Context                  Domain           Count APT Exception
  61    2 a8a0 00000000036eeb30      b220 Enabled  0000000000000000:0000000000000000 000000000112bef0     0 MTA (Finalizer)
...
       OSID     Special thread type
   35   59f8    IOCompletion 
   36   7f2c    DbgHelper 
   37    eb0    GC SuspendEE 
   60   19d0    GC 
   61   a8a0    Finalizer 
   62   547c    Timer 
   63   8c2c    ADUnloadHelper 
   64    2fc    ThreadpoolWorker 
   87   8ce4    ThreadpoolWorker 
...
复制代码
  1. -live:与或线程有关联的线程;
  2. -special:特殊线程列表:
  • special命令非常有用,它能够帮助你分清楚某个线程是什么线程。
  • Special thread type列有如下取值:
  • GC:垃圾回收线程;
  • Finalizer:对象释放线程,.Net至少有一个,用于专门处理对象释放。
  • Timer:计时器线程;
  • ThreadpoolWorker:工作者线程;
  • IOCompletion:I/O线程;
  • ADUnloadHelper:
  • DbgHelper:
  • GC SuspendEE:

  3、clrstack [-a] [-l] [-p]

  当前线程的托管代码调用堆栈。

  • -p 显示托管函数的参数。
  • -l 显示在一个框架里局部变量的信息。SOS调试扩展无法检索局部变量的名字,所以局部变量的输出格式为<local address> = <value>。
  • -a (all) 选项是-l和-p组合的快捷方式。
复制代码
0:083> !clrstack
OS Thread Id: 0x6914 (83)
Child-SP         RetAddr          Call Site
000000000b65cae0 000007ff00cf0313 System.String.Concat(System.String, System.String, System.String)
000000000b65cb40 000007ff012b0ac5 xx.TE.Web.Service.Management.CompositeFieldService.GetCompositeFieldContent(System.Web.HttpContextBase, System.String, Comit.TE.Web.Domain.Management.CompositeField, Int32)
000000000b65cfd0 000007ff0126d39b xx.TE.Web.Areas.Cases.Controllers.WritDataBagController.PageWritContent(System.String, Int32)
000000000b65d410 000007fee7ca082c DynamicClass.lambda_method(System.Runtime.CompilerServices.ExecutionScope, System.Web.Mvc.ControllerBase, System.Object[])
000000000b65d460 000007fee7ca31ef System.Web.Mvc.ReflectedActionDescriptor.Execute(System.Web.Mvc.ControllerContext, System.Collections.Generic.IDictionary`2<System.String,System.Object>)
000000000b65d4c0 000007fee7ca47b5 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(System.Web.Mvc.ControllerContext, System.Web.Mvc.ActionDescriptor, System.Collections.Generic.IDictionary`2<System.String,System.Object>)
...
复制代码

  这个命令是sos.dll的支持,如果希望显示当前线程的非托管代码调用堆栈,应该使用kb

  此处还有一种写法~*e!clrstack:此命令用于显示所有线程的托管代码调用堆栈。

  4、DumpStack

  !clrstack只显示托管代码,而!kb只显示非托管代码。而DumpStack则是以上两个命令的综合版。既显示托管代码堆栈也显示非托管代码堆栈。-EE 选项使DumpStack命令只显示托管函数。

复制代码
0:083> !dumpstack
OS Thread Id: 0x6914 (83)
Child-SP         RetAddr          Call Site
000000000b65c468 000007fefd6d10dc ntdll!ZwWaitForSingleObject+0xa
000000000b65c470 000007fef128d0e0 KERNELBASE!WaitForSingleObjectEx+0x79
000000000b65c510 000007fef128d1e3 mscorwks!MethodTableBuilder::MethodSignature::GetMethodAttributes+0xa8
000000000b65c560 000007fef138e250 mscorwks!CLREvent::WaitEx+0x63
000000000b65c610 000007fef15a9596 mscorwks!SVR::gc_heap::wait_for_gc_done+0x80
000000000b65c650 000007fef17339cc mscorwks!SVR::GCHeap::GarbageCollectGeneration+0x206
000000000b65c6b0 000007fef13996a2 mscorwks!SVR::gc_heap::try_allocate_more_space+0x1ac
000000000b65c7a0 000007fef136ecef mscorwks!SVR::gc_heap::allocate_more_space+0x32
000000000b65c7f0 000007fef12d7278 mscorwks!SVR::gc_heap::allocate_large_object+0x5f
000000000b65c860 000007fef12d758e mscorwks!SVR::GCHeap::Alloc+0x198
000000000b65c8a0 000007fef17b9433 mscorwks!SlowAllocateString+0x7e
000000000b65c920 000007fef051beec mscorwks!FramedAllocateString+0xd3
000000000b65cae0 000007ff00cf0313 mscorlib_ni!System.String.Concat(System.String, System.String, System.String)+0x4c
000000000b65cb40 000007ff012b0ac5 xxx_TE_Web_Service!xxx.TE.Web.Service.Management.CompositeFieldService.GetCompositeFieldContent(System.Web.HttpContextBase, System.String, Comit.TE.Web.Domain.Management.CompositeField, Int32)+0x13d3
000000000b65cfd0 000007ff0126d39b xxx_TE_Web!xxx.TE.Web.Areas.Cases.Controllers.WritDataBagController.PageWritContent(System.String, Int32)+0x6a5
...
复制代码

  5、进程信息

  在调试会话中,有时候获得关于被调试进程的更多信息是非常有用的。例如,内存使用量,环境变量,处理时间等,这些数据都是非常有用的。要在调试时将这些信息转储出来,可以使用ProInfo命令。语法如下:

!ProcInfo [-env][-time][-mem]

  其中-env、-time、-mem等开关控制着所要显示的进程信息。如果没有指定任何开关,那么会显示所有者三类信息。

  在时候调试Dump File里面试不支持这个命令的。

复制代码
0:000> !ProcInfo
---------------------------------------
Environment
=::=::\
ALLUSERSPROFILE=C:\ProgramData
ANALYSIS_PATH=D:\LoadRunner\
APPDATA=C:\Users\ChenZhuo\AppData\Roaming
ClassPath=.;%JAVE_HOME%lib/rt.jar;C:\Program Files\Java\jdk1.6.0_24lib/tools.jar
CommonProgramFiles=C:\Program Files\Common Files
COMPUTERNAME=CZZ
ComSpec=C:\Windows\system32\cmd.exe
CURR_DIR=D:\LoadRunner\dat\Setup\LoadRunner\MSBuild\..\..\..\..
FP_NO_HOST_CHECK=NO
FTP_PASSIVE=1
HOMEDRIVE=C:
HOMEPATH=\Users\ChenZhuo
JAVA_HOME=C:\Program Files\Java\jdk1.6.0_24
LG_PATH=D:\LoadRunner\
LOCALAPPDATA=C:\Users\ChenZhuo\AppData\Local
LOGGER_CONFIG_PATH=D:\LoadRunner\dat\ltlogconf.xml
LOGONSERVER=\\CZZ
LOG_FILE=C:\Users\ChenZhuo\AppData\Local\Temp\ihp_custom_batches.log
LR_PATH=D:\LoadRunner\
LR_ROOT=D:\LoadRunner\
NUMBER_OF_PROCESSORS=4
OS=Windows_NT
Path=C:\Program Files\Debugging Tools for Windows (x86)\winext\arcade;%JAVA_HOME%/bin;c:\oracle\product\10.2.0\client_1\bin;C:\Program Files\Intel\iCLS Client\;C:\Windows\system32;...省略
PROCESSOR_ARCHITECTURE=x86
PROCESSOR_IDENTIFIER=x86 Family 6 Model 42 Stepping 7, GenuineIntel
PROCESSOR_LEVEL=6
PROCESSOR_REVISION=2a07
ProgramData=C:\ProgramData
ProgramFiles=C:\Program Files
---------------------------------------
Process Times
Process Started at: 2014 May 30 16:23:12.21
Kernel CPU time   : 0 days 00:00:00.01
User   CPU time   : 0 days 00:00:00.01
Total  CPU time   : 0 days 00:00:00.02
---------------------------------------
Process Memory
WorkingSetSize:     6820 KB       PeakWorkingSetSize:     6820 KB
VirtualSize:       97744 KB       PeakVirtualSize:       98272 KB
PagefileUsage:      6816 KB       PeakPagefileUsage:      6824 KB
---------------------------------------
54 percent of memory is in use.

Memory Availability (Numbers in MB)

                     Total        Avail
Physical Memory       3486         1585
Page File             4095         3019
Virtual Memory        2047         1819
复制代码

五、垃圾回收

  1、GCRoot

  !GCRoot是一个非常有用的命令,它能够帮助我们发现某对象上目前还存在的有效引用。这也是为什么GC还不回收这个对象的原因。这个信息可以很好的帮助我们分析那些本应该没有引用,但却一直还存在有效引用的对象,由此发现我们代码中潜在的内存泄漏,同时我们也可以观察到哪些对象是目前没有引用了。

复制代码
0:000> !gcroot 000000011f993008
Note: Roots found on stacks may be false positives. Run "!help gcroot" for
more info.
Scan Thread 22 OSTHread 3468
Scan Thread 61 OSTHread a8a0
Scan Thread 62 OSTHread 547c
Scan Thread 63 OSTHread 8c2c
Scan Thread 64 OSTHread 2fc
Scan Thread 65 OSTHread 90a4
RSP:aced0e8:Root:000000012f453b98(IBatisNet.DataMapper.MappedStatements.SelectMappedStatement)->
000000014f459390(IBatisNet.DataMapper.SqlMapper)->
000000014f459480(System.Collections.Specialized.HybridDictionary)->
000000014f5d8140(System.Collections.Hashtable)->
00000001ff6f5e38(System.Collections.Hashtable+bucket[])->
00000000ff5e7298(IBatisNet.DataMapper.Configuration.Cache.CacheModel)->
00000000ff5e7560(IBatisNet.DataMapper.Configuration.Cache.Memory.MemoryCacheControler)->
00000000ff5e75d8(System.Collections.Hashtable+SyncHashtable)->
00000000ff5e7580(System.Collections.Hashtable)->
000000028f350080(System.Collections.Hashtable+bucket[])->
000000011f992fd8(IBatisNet.DataMapper.Configuration.Cache.CacheKey)->
000000011f993008(System.Collections.ArrayList)
Scan Thread 66 OSTHread 11d0
Scan Thread 67 OSTHread 2928
Scan Thread 68 OSTHread a2a4
Scan Thread 69 OSTHread 2554
复制代码

  如上面能够查看到某对象被引用的关系。

六、其他

  1、EEVersion

  显示公共语言运行时版本。

0:061> !EEVersion
2.0.50727.5477 free
Server mode with 24 gc heaps
SOS Version: 2.0.50727.5477 retail build

  上面的输出显示有24个GC堆(24核CPU),.Net版本为2.0.50727.5477。同时,该命令还输出了正在使用的SOS版本。

  2、EEStack [-short] [-EE]

  对进程中的所有线程执行DumpStack命令,-EE 选项被直接传递给DumpStack命令。-short 参数限制输入内容为以下线程种类:

  1. 已经被锁定的线程。
  2. 为了允许垃圾收集已经被迟延的线程。
  3. 目前处于托管代码中的线程。
复制代码
0:083> !EEStack
---------------------------------------------
Thread  22
Child-SP         RetAddr          Call Site
000000000189fb88 000007fefd6d16ad ntdll!ZwRemoveIoCompletion+0xa
000000000189fb90 000000007750a4e1 KERNELBASE!GetQueuedCompletionStatus+0x39
000000000189fbf0 000007fef5701f7b kernel32!GetQueuedCompletionStatusStub+0x11
000000000189fc30 000007fef5702024 w3tp!THREAD_POOL_DATA::ThreadPoolThread+0x3b
000000000189fc80 000007fef57020a1 w3tp!THREAD_POOL_DATA::ThreadPoolThread+0x34
000000000189fcb0 000000007751652d w3tp!THREAD_MANAGER::ThreadManagerThread+0x61
000000000189fce0 000000007764c541 kernel32!BaseThreadInitThunk+0xd
000000000189fd10 0000000000000000 ntdll!RtlUserThreadStart+0x1d
---------------------------------------------
Thread  61
Child-SP         RetAddr          Call Site
000000000946f388 000007fefd6d10dc ntdll!ZwWaitForSingleObject+0xa
000000000946f390 000007fef128d0e0 KERNELBASE!WaitForSingleObjectEx+0x79
000000000946f430 000007fef128d1e3 mscorwks!MethodTableBuilder::MethodSignature::GetMethodAttributes+0xa8
000000000946f480 000007fef124bbf9 mscorwks!CLREvent::WaitEx+0x63
000000000946f530 000007fef124bd82 mscorwks!SVR::WaitForFinalizerEvent+0x49
...
复制代码

Leave a Reply