利用SOS分析调试托管代码--(2)
- 查看线程和同步块
- 查看GC
- 其他诊断工具
1.查看托管线程
Threads命令显示进程中的所有托管线程及统计信息。-special选项显示由 CLR 创建的所有特殊线程,包括GC线程、调试器帮助程序线程、终结器线程、 AppDomain卸载线程和线程池计时器线程。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
!Threads -special
ThreadCount: 2
UnstartedThread: 0
BackgroundThread: 1
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
PreEmptive GC Alloc Lock
ID OSID ThreadOBJ State GC Context Domain Count APT Exception
11820 1 2e2c 003e7ee8 8a028 Enabled 01b0ba14:01b0c004 003e16b0 1 MTA
10364 2 287c 003e99a0 b228 Enabled 00000000:00000000 003e16b0 0 MTA (Finalizer)
OSID Special thread type
10364 287c Finalizer
可以看到当前有2个线程,1个属于后台线程。线程2是终结器线程。我们还可以看到线程1存在一个锁。
2.查看线程状态
线程State只是一个值,我们需要得到具体的描述,可以利用ThreadState命令显示线程的状态。value参数为Threads输出中的State字段的值。
我们查看线程1的状态。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
!ThreadState 8a028
Debug Suspend Pending
Legal to Join
CoInitialized
In Multi Threaded Apartment
Sync Suspended
3.查询线程同步块
线程同步块结构是一个容器,用于存放无需为每个对象创建的额外信息。比如COM互操作数据、哈希代码和用于线程安全操作的锁定信息。
我们可以用syncblk命令查询所有的线程同步块。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
!SyncBlk
Index SyncBlock MonitorHeld Recursion Owning Thread Info SyncBlock Owner
1 0043f9ac 1 1 003e7ee8 2e2c11820 01b0b22c Wuhong.SOSTest.Complex
-----------------------------
Total 1
CCW 0
RCW 0
ComClassFactory 0
Free 0
可以看到有线程1的类型为Wuhong.SOSTest.Complex的对象上拥有1个同步块。
1.查看托管堆统计
HeapStat命令显示每个堆的生成大小及每个堆上各生成的可用空间总量。-inclUnrooted选项包括有关不再为根的垃圾回收集合堆中的托管对象的信息。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
!HeapStat -inclUnrooted
Heap Gen0 Gen1 Gen2 LOH
Heap0 45048 12 12 8784
Free space: Percentage
Heap0 12 0 0 64SOH: 0% LOH: 0%
Unrooted objects: Percentage
Heap0 11328 0 0 0SOH: 25% LOH: 0%
2.查看GC句柄
利用GCHandles命令可以显示进程中的垃圾回收器句柄的统计信息。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
!GCHandles
GC Handle Statistics:
Strong Handles: 10
Pinned Handles: 4
Async Pinned Handles: 0
Ref Count Handles: 0
Weak Long Handles: 0
Weak Short Handles: 0
Other Handles: 0
Statistics:
MT Count TotalSize Class Name
605ff5e8 1 12 System.Object
60601b18 1 28 System.SharedStatics
60603670 1 36 System.Security.PermissionSet
605fffcc 1 48 System.Threading.Thread
605ffde8 1 84 System.ExecutionEngineException
605ffd9c 1 84 System.StackOverflowException
605ffd50 1 84 System.OutOfMemoryException
605ffc0c 1 84 System.Exception
60600ec8 1 112 System.AppDomain
605ffe34 2 168 System.Threading.ThreadAbortException
605b6c28 3 8720 System.Object[]
Total 14 objects
可以看到进程中一共有4个固定句柄和10个强类型句柄。
3.查看终结器队列
利用FinalizeQueue命令,可以显示所有已进行终结注册的对象。-allReady 选项显示所有准备终止的对象,无论它们已被垃圾回收标记成这样,还是将被下一个垃圾回收标记。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
!FinalizeQueue
SyncBlocks to be cleaned up: 0
MTA Interfaces to be released: 0
STA Interfaces to be released: 0
----------------------------------
generation 0 has 3 finalizable objects (00428bb0->00428bbc)
generation 1 has 0 finalizable objects (00428bb0->00428bb0)
generation 2 has 0 finalizable objects (00428bb0->00428bb0)
Ready for finalization 0 objects (00428bbc->00428bbc)
Statistics for all finalizable objects (including all objects ready for finalization):
MT Count TotalSize Class Name
605ff4d0 1 20 Microsoft.Win32.SafeHandles.SafePEFileHandle
60605efc 1 44 System.Threading.ReaderWriterLock
605fffcc 1 48 System.Threading.Thread
Total 3 objects
4.查询对象的根
利用GCRoot可以显示有关对指定地址处的对象的引用(或根)的信息。搜寻范围是整个托管堆和句柄表,同时还搜索终结器队列。这个命令可以用来确认对象为什么没有被垃圾收集。
比如我们想查看DumpObj小节中类型为Wuhong.SOSTest.Complex的对象的根。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
!GCRoot 0x01b0b22c
Note: Roots found on stacks may be false positives. Run "!help gcroot" for
more info.
Scan Thread 11820 OSTHread 2e2c
ESP:28ecbc:Root: 01b0b22c(Wuhong.SOSTest.Complex)
ESP:28edfc:Root: 01b0b22c(Wuhong.SOSTest.Complex)
ESP:28f08c:Root: 01b0b22c(Wuhong.SOSTest.Complex)
ESP:28f09c:Root: 01b0b22c(Wuhong.SOSTest.Complex)
ESP:28f0e0:Root: 01b0b22c(Wuhong.SOSTest.Complex)
ESP:28f0e4:Root: 01b0b22c(Wuhong.SOSTest.Complex)
Scan Thread 10364 OSTHread 287c
可以看到这个对象在线程1中有6个引用。
5.查询对象在GC堆中的位置
GCWhere命令显示垃圾回收堆中参数传入的位置和大小。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
!GCWhere 0x01b0b22c
Address Gen Heap segment begin allocated size
01b0b22c 0 0 01b00000 01b01000 01b0c010 0x18(24)
6.查询GC堆
只要得到对象在堆中的地址,就可以用DumpHeap显示有关GC堆的信息和和相关收统计信息。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
!DumpHeap 01b0b22c
Address MT Size
01b0b22c 00133918 24
01b0b244 605ff9ac 64
object 01b0b284: does not have valid MT
curr_object: 01b0b284
Last good object: 01b0b244
----------------
02b01000 003e91d8 16 Free
02b01010 605b6c28 4096
02b02010 003e91d8 16 Free
02b02020 605b6c28 528
02b02230 003e91d8 16 Free
02b02240 605b6c28 4096
02b03240 003e91d8 16 Free
total 0 objects
Statistics:
MT Count TotalSize Class Name
00133918 1 24 Wuhong.SOSTest.Complex
605ff9ac 1 64 System.String
003e91d8 4 64 Free
605b6c28 3 8720 System.Object[]
Total 9 objects
我们可以看到堆中从命令输入地址开始的对象的排列,另外我们还注意到有个对象的方法表无效了。
1.查看进程信息
利用ProcInfo命令可以详细显示进程的环境变量、内核CPU时间和内存使用统计信息。这些信息在性能调试中非常有用。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
!ProcInfo
---------------------------------------
Environment
ALLUSERSPROFILE=C:\ProgramData
APPDATA=C:\Users\Administrator\AppData\Roaming
CommonProgramFiles=C:\Program Files\Common Files
COMPUTERNAME=WUHONG
ComSpec=C:\Windows\system32\cmd.exe
FP_NO_HOST_CHECK=NO
HOMEDRIVE=C:
HOMEPATH=\Users\Administrator
lib=C:\Program Files\SQLXML 4.0\bin\
……
……
……
---------------------------------------
Process Times
Process Started at: 2011 Apr 27 15:35:42.44
Kernel CPU time : 0 days 00:00:31.93
User CPU time : 0 days 00:04:15.56
Total CPU time : 0 days 00:04:47.49
---------------------------------------
Process Memory
WorkingSetSize: 487144 KB PeakWorkingSetSize: 497100 KB
VirtualSize: 906484 KB PeakVirtualSize: 913984 KB
PagefileUsage: 235248 KB PeakPagefileUsage: 243036 KB
---------------------------------------
67 percent of memory is in use.
Memory Availability (Numbers in MB)
Total Avail
Physical Memory 3583 1153
Page File 4095 3056
Virtual Memory 2047 1162
2.查询曾经出现的OOM状况
利用AnalyzeOOM命令可以显示对GC堆进行分配请求时发生的最后 OOM 的信息。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
!AnalyzeOOM
There was no managed OOM due to allocations on the GC heap
3.查询对象所在的AppDomain
利用FindAppDomain命令可以确定指定地址处的对象的AppDomain。
比如我们要确定DumpObj小节中类型为Wuhong.SOSTest.Complex的对象所在的AppDomain。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
!FindAppDomain 0x01b0b22c
AppDomain: 003e16b0
Name: Wuhong.SOSTest.exe
ID: 1
4.验证GC堆或对象的有效性
在DumpHeap小节我们注意到了在GC堆上有1个对象的方法表无效了。可以用VerifyHeap命令验证整个堆是否有损坏,也可以用VerifyObj命令验证具体的对象。
对象损坏可能有多种原因,比如内存越界修改等。具体原因需要详细分析损坏的对象。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
!VerifyHeap
-verify will only produce output if there are errors in the heap
object 01b0b284: does not have valid MT
curr_object: 01b0b284
Last good object: 01b0b244
----------------