ObjSize EHInfo
FinalizeQueue BPMD (bpmd)
PrintException (pe) COMState
-TraverseHeap
+TraverseHeap
Examining CLR data structures Diagnostic Utilities
----------------------------- -----------------------------
RCWCleanupList VMStat
DumpIL MinidumpMode
DumpRCW AnalyzeOOM (ao)
-DumpCCW
+DumpCCW SuppressJitOptimization
Examining the GC history Other
----------------------------- -----------------------------
>> I got the following error message. Now what?
- 0:000> .loadby sos coreclr
- 0:000> !DumpStackObjects
- Failed to find runtime DLL (coreclr.dll), 0x80004005
- Extension commands need coreclr.dll in order to have something to do.
- 0:000>
+ 0:000> .loadby sos coreclr
+ 0:000> !DumpStackObjects
+ Failed to find runtime DLL (coreclr.dll), 0x80004005
+ Extension commands need coreclr.dll in order to have something to do.
+ 0:000>
This means that the coreclr is not loaded yet, or has been unloaded. You need to
wait until your managed program is running in order to use these commands. If
You might find an object pointer by running !DumpStackObjects and choosing
from the resultant list. Here is a simple object:
- 0:000> !DumpObj a79d40
- Name: Customer
- MethodTable: 009038ec
- EEClass: 03ee1b84
- Size: 20(0x14) bytes
- (C:\pub\unittest.exe)
- Fields:
- MT Field Offset Type VT Attr Value Name
- 009038ec 4000008 4 Customer 0 instance 00a79ce4 name
- 009038ec 4000009 8 Bank 0 instance 00a79d2c bank
+ 0:000> !DumpObj a79d40
+ Name: Customer
+ MethodTable: 009038ec
+ EEClass: 03ee1b84
+ Size: 20(0x14) bytes
+ (C:\pub\unittest.exe)
+ Fields:
+ MT Field Offset Type VT Attr Value Name
+ 009038ec 4000008 4 Customer 0 instance 00a79ce4 name
+ 009038ec 4000009 8 Bank 0 instance 00a79d2c bank
Note that fields of type Customer and Bank are themselves objects, and you can
run !DumpObj on them too. You could look at the field directly in memory using
COMMAND: da.
COMMAND: dumparray.
!DumpArray
- [-start <startIndex>]
- [-length <length>]
- [-details]
- [-nofields]
- <array object address>
+ [-start <startIndex>]
+ [-length <length>]
+ [-details]
+ [-nofields]
+ <array object address>
This command allows you to examine elements of an array object.
The arguments in detail:
Example output:
- 0:000> !dumparray -start 2 -length 3 -details 00ad28d0
- Name: Value[]
- MethodTable: 03e41044
- EEClass: 03e40fc0
- Size: 132(0x84) bytes
- Array: Rank 1, Number of elements 10, Type VALUETYPE
- Element Type: Value
- [2] 00ad28f0
- Name: Value
- MethodTable 03e40f4c
- EEClass: 03ef1698
- Size: 20(0x14) bytes
- (C:\bugs\225271\arraytest.exe)
- Fields:
- MT Field Offset Type Attr Value Name
- 5b9a628c 4000001 0 System.Int32 instance 2 x
- 5b9a628c 4000002 4 System.Int32 instance 4 y
- 5b9a628c 4000003 8 System.Int32 instance 6 z
- [3] 00ad28fc
- Name: Value
- MethodTable 03e40f4c
- EEClass: 03ef1698
- Size: 20(0x14) bytes
- (C:\bugs\225271\arraytest.exe)
- Fields:
- MT Field Offset Type Attr Value Name
- 5b9a628c 4000001 0 System.Int32 instance 3 x
- 5b9a628c 4000002 4 System.Int32 instance 6 y
- 5b9a628c 4000003 8 System.Int32 instance 9 z
- [4] 00ad2908
- Name: Value
- MethodTable 03e40f4c
- EEClass: 03ef1698
- Size: 20(0x14) bytes
- (C:\bugs\225271\arraytest.exe)
- Fields:
- MT Field Offset Type Attr Value Name
- 5b9a628c 4000001 0 System.Int32 instance 4 x
- 5b9a628c 4000002 4 System.Int32 instance 8 y
- 5b9a628c 4000003 8 System.Int32 instance 12 z
+ 0:000> !dumparray -start 2 -length 3 -details 00ad28d0
+ Name: Value[]
+ MethodTable: 03e41044
+ EEClass: 03e40fc0
+ Size: 132(0x84) bytes
+ Array: Rank 1, Number of elements 10, Type VALUETYPE
+ Element Type: Value
+ [2] 00ad28f0
+ Name: Value
+ MethodTable 03e40f4c
+ EEClass: 03ef1698
+ Size: 20(0x14) bytes
+ (C:\bugs\225271\arraytest.exe)
+ Fields:
+ MT Field Offset Type Attr Value Name
+ 5b9a628c 4000001 0 System.Int32 instance 2 x
+ 5b9a628c 4000002 4 System.Int32 instance 4 y
+ 5b9a628c 4000003 8 System.Int32 instance 6 z
+ [3] 00ad28fc
+ Name: Value
+ MethodTable 03e40f4c
+ EEClass: 03ef1698
+ Size: 20(0x14) bytes
+ (C:\bugs\225271\arraytest.exe)
+ Fields:
+ MT Field Offset Type Attr Value Name
+ 5b9a628c 4000001 0 System.Int32 instance 3 x
+ 5b9a628c 4000002 4 System.Int32 instance 6 y
+ 5b9a628c 4000003 8 System.Int32 instance 9 z
+ [4] 00ad2908
+ Name: Value
+ MethodTable 03e40f4c
+ EEClass: 03ef1698
+ Size: 20(0x14) bytes
+ (C:\bugs\225271\arraytest.exe)
+ Fields:
+ MT Field Offset Type Attr Value Name
+ 5b9a628c 4000001 0 System.Int32 instance 4 x
+ 5b9a628c 4000002 4 System.Int32 instance 8 y
+ 5b9a628c 4000003 8 System.Int32 instance 12 z
\\
For example:
- 0:000> !dumpdelegate
+ 0:000> !dumpdelegate
Target Method Name
000001461bacb0d8 00007ffc5c894b80 ConsoleApp16.Program.InstanceMethod()
000001461bacb098 00007ffc5c894b68 ConsoleApp16.Program.StaticMethod()
When called without options, the output is first a list of objects in the heap,
followed by a report listing all the types found, their size and number:
- 0:000> !dumpheap
- Address MT Size
- 00a71000 0015cde8 12 Free
- 00a7100c 0015cde8 12 Free
- 00a71018 0015cde8 12 Free
- 00a71024 5ba58328 68
- 00a71068 5ba58380 68
- 00a710ac 5ba58430 68
- 00a710f0 5ba5dba4 68
- ...
- total 619 objects
- Statistics:
- MT Count TotalSize Class Name
- 5ba7607c 1 12 System.Security.Permissions.HostProtectionResource
- 5ba75d54 1 12 System.Security.Permissions.SecurityPermissionFlag
- 5ba61f18 1 12 System.Collections.CaseInsensitiveComparer
- ...
- 0015cde8 6 10260 Free
- 5ba57bf8 318 18136 System.String
- ...
+ 0:000> !dumpheap
+ Address MT Size
+ 00a71000 0015cde8 12 Free
+ 00a7100c 0015cde8 12 Free
+ 00a71018 0015cde8 12 Free
+ 00a71024 5ba58328 68
+ 00a71068 5ba58380 68
+ 00a710ac 5ba58430 68
+ 00a710f0 5ba5dba4 68
+ ...
+ total 619 objects
+ Statistics:
+ MT Count TotalSize Class Name
+ 5ba7607c 1 12 System.Security.Permissions.HostProtectionResource
+ 5ba75d54 1 12 System.Security.Permissions.SecurityPermissionFlag
+ 5ba61f18 1 12 System.Collections.CaseInsensitiveComparer
+ ...
+ 0015cde8 6 10260 Free
+ 5ba57bf8 318 18136 System.String
+ ...
"Free" objects are simply regions of space the garbage collector can use later.
If 30%% or more of the heap contains "Free" objects, the process may suffer from
combined with a high rate of allocation. Here is example output where !DumpHeap
provides a warning about fragmentation:
- <After the Statistics section>
- Fragmented blocks larger than 1MB:
- Addr Size Followed by
- 00a780c0 1.5MB 00bec800 System.Byte[]
- 00da4e38 1.2MB 00ed2c00 System.Byte[]
- 00f16df0 1.2MB 01044338 System.Byte[]
+ <After the Statistics section>
+ Fragmented blocks larger than 1MB:
+ Addr Size Followed by
+ 00a780c0 1.5MB 00bec800 System.Byte[]
+ 00da4e38 1.2MB 00ed2c00 System.Byte[]
+ 00f16df0 1.2MB 01044338 System.Byte[]
The arguments in detail:
The start/end parameters can be obtained from the output of !EEHeap -gc. For
example, if you only want to list objects in the large heap segment:
- 0:000> !eeheap -gc
- Number of GC Heaps: 1
- generation 0 starts at 0x00c32754
- generation 1 starts at 0x00c32748
- generation 2 starts at 0x00a71000
- segment begin allocated size
- 00a70000 00a71000 010443a8 005d33a8(6108072)
- Large object heap starts at 0x01a71000
- segment begin allocated size
- 01a70000 01a71000 01a75000 0x00004000(16384)
- Total Size 0x5d73a8(6124456)
- ------------------------------
- GC Heap Size 0x5d73a8(6124456)
-
- 0:000> !dumpheap 1a71000 1a75000
- Address MT Size
- 01a71000 5ba88bd8 2064
- 01a71810 0019fe48 2032 Free
- 01a72000 5ba88bd8 4096
- 01a73000 0019fe48 4096 Free
- 01a74000 5ba88bd8 4096
- total 5 objects
- Statistics:
- MT Count TotalSize Class Name
- 0019fe48 2 6128 Free
- 5ba88bd8 3 10256 System.Object[]
- Total 5 objects
+ 0:000> !eeheap -gc
+ Number of GC Heaps: 1
+ generation 0 starts at 0x00c32754
+ generation 1 starts at 0x00c32748
+ generation 2 starts at 0x00a71000
+ segment begin allocated size
+ 00a70000 00a71000 010443a8 005d33a8(6108072)
+ Large object heap starts at 0x01a71000
+ segment begin allocated size
+ 01a70000 01a71000 01a75000 0x00004000(16384)
+ Total Size 0x5d73a8(6124456)
+ ------------------------------
+ GC Heap Size 0x5d73a8(6124456)
+
+ 0:000> !dumpheap 1a71000 1a75000
+ Address MT Size
+ 01a71000 5ba88bd8 2064
+ 01a71810 0019fe48 2032 Free
+ 01a72000 5ba88bd8 4096
+ 01a73000 0019fe48 4096 Free
+ 01a74000 5ba88bd8 4096
+ total 5 objects
+ Statistics:
+ MT Count TotalSize Class Name
+ 0019fe48 2 6128 Free
+ 5ba88bd8 3 10256 System.Object[]
+ Total 5 objects
Finally, if GC heap corruption is present, you may see an error like this:
- 0:000> !dumpheap -stat
- object 00a73d24: does not have valid MT
- curr_object : 00a73d24
- Last good object: 00a73d14
- ----------------
+ 0:000> !dumpheap -stat
+ object 00a73d24: does not have valid MT
+ curr_object : 00a73d24
+ Last good object: 00a73d14
+ ----------------
That indicates a serious problem. See the help for !VerifyHeap for more
information on diagnosing the cause.
a value class is not a first-class object with it's own MethodTable as the
first field. For example:
- 0:000> !DumpObj a79d98
- Name: Mainy
- MethodTable: 009032d8
- EEClass: 03ee1424
- Size: 28(0x1c) bytes
- (C:\pub\unittest.exe)
- Fields:
- MT Field Offset Type Attr Value Name
- 0090320c 4000010 4 VALUETYPE instance 00a79d9c m_valuetype
- 009032d8 400000f 4 CLASS static 00a79d54 m_sExcep
+ 0:000> !DumpObj a79d98
+ Name: Mainy
+ MethodTable: 009032d8
+ EEClass: 03ee1424
+ Size: 28(0x1c) bytes
+ (C:\pub\unittest.exe)
+ Fields:
+ MT Field Offset Type Attr Value Name
+ 0090320c 4000010 4 VALUETYPE instance 00a79d9c m_valuetype
+ 009032d8 400000f 4 CLASS static 00a79d54 m_sExcep
m_valuetype is a value type. The value in the MT column (0090320c) is the
MethodTable for it, and the Value column provides the start address:
- 0:000> !DumpVC 0090320c 00a79d9c
- Name: Funny
- MethodTable 0090320c
- EEClass: 03ee14b8
- Size: 28(0x1c) bytes
- (C:\pub\unittest.exe)
- Fields:
- MT Field Offset Type Attr Value Name
- 0090320c 4000001 0 CLASS instance 00a743d8 signature
- 0090320c 4000002 8 System.Int32 instance 2345 m1
- 0090320c 4000003 10 System.Boolean instance 1 b1
- 0090320c 4000004 c System.Int32 instance 1234 m2
- 0090320c 4000005 4 CLASS instance 00a79d98 backpointer
+ 0:000> !DumpVC 0090320c 00a79d9c
+ Name: Funny
+ MethodTable 0090320c
+ EEClass: 03ee14b8
+ Size: 28(0x1c) bytes
+ (C:\pub\unittest.exe)
+ Fields:
+ MT Field Offset Type Attr Value Name
+ 0090320c 4000001 0 CLASS instance 00a743d8 signature
+ 0090320c 4000002 8 System.Int32 instance 2345 m1
+ 0090320c 4000003 10 System.Boolean instance 1 b1
+ 0090320c 4000004 c System.Int32 instance 1234 m2
+ 0090320c 4000005 4 CLASS instance 00a79d98 backpointer
!DumpVC is quite a specialized function. Some managed programs make heavy use
of value classes, while others do not.
For example, !DumpObj lists a size of 20 bytes for this Customer object:
- 0:000> !do a79d40
- Name: Customer
- MethodTable: 009038ec
- EEClass: 03ee1b84
- Size: 20(0x14) bytes
- (C:\pub\unittest.exe)
- Fields:
- MT Field Offset Type Attr Value Name
- 009038ec 4000008 4 CLASS instance 00a79ce4 name
- 009038ec 4000009 8 CLASS instance 00a79d2c bank
- 009038ec 400000a c System.Boolean instance 1 valid
+ 0:000> !do a79d40
+ Name: Customer
+ MethodTable: 009038ec
+ EEClass: 03ee1b84
+ Size: 20(0x14) bytes
+ (C:\pub\unittest.exe)
+ Fields:
+ MT Field Offset Type Attr Value Name
+ 009038ec 4000008 4 CLASS instance 00a79ce4 name
+ 009038ec 4000009 8 CLASS instance 00a79d2c bank
+ 009038ec 400000a c System.Boolean instance 1 valid
but !ObjSize lists 152 bytes:
- 0:000> !ObjSize a79d40
- sizeof(00a79d40) = 152 ( 0x98) bytes (Customer)
+ 0:000> !ObjSize a79d40
+ sizeof(00a79d40) = 152 ( 0x98) bytes (Customer)
This is because a Customer points to a Bank, has a name, and the Bank points to
an Address string. You can use !ObjSize to identify any particularly large
This command lists the objects registered for finalization. Here is output from
a simple program:
- 0:000> !finalizequeue
- SyncBlocks to be cleaned up: 0
- MTA Interfaces to be released: 0
- STA Interfaces to be released: 1
- generation 0 has 4 finalizable objects (0015bc90->0015bca0)
- generation 1 has 0 finalizable objects (0015bc90->0015bc90)
- generation 2 has 0 finalizable objects (0015bc90->0015bc90)
- Ready for finalization 0 objects (0015bca0->0015bca0)
- Statistics:
- MT Count TotalSize Class Name
- 5ba6cf78 1 24 Microsoft.Win32.SafeHandles.SafeFileHandle
- 5ba5db04 1 68 System.Threading.Thread
- 5ba73e28 2 112 System.IO.StreamWriter
- Total 4 objects
+ 0:000> !finalizequeue
+ SyncBlocks to be cleaned up: 0
+ MTA Interfaces to be released: 0
+ STA Interfaces to be released: 1
+ generation 0 has 4 finalizable objects (0015bc90->0015bca0)
+ generation 1 has 0 finalizable objects (0015bc90->0015bc90)
+ generation 2 has 0 finalizable objects (0015bc90->0015bc90)
+ Ready for finalization 0 objects (0015bca0->0015bca0)
+ Statistics:
+ MT Count TotalSize Class Name
+ 5ba6cf78 1 24 Microsoft.Win32.SafeHandles.SafeFileHandle
+ 5ba5db04 1 68 System.Threading.Thread
+ 5ba73e28 2 112 System.IO.StreamWriter
+ Total 4 objects
The GC heap is divided into generations, and objects are listed accordingly. We
see that only generation 0 (the youngest generation) has any objects registered
Given an address in managed JITTED code, IP2MD attempts to find the MethodDesc
associated with it. For example, this output from K:
- 0:000> K
- ChildEBP RetAddr
- 00a79c78 03ef02ab image00400000!Mainy.Top()+0xb
- 00a79c78 03ef01a6 image00400000!Mainy.Level(Int32)+0xb
- 00a79c78 5d3725a1 image00400000!Mainy.Main()+0xee
- 0012ea04 5d512f59 clr!CallDescrWorkerInternal+0x30
- 0012ee34 5d7946aa clr!CallDescrWorker+0x109
-
- 0:000> !IP2MD 03ef01a6
- MethodDesc: 00902f40
- Method Name: Mainy.Main()
- Class: 03ee1424
- MethodTable: 009032d8
- mdToken: 0600000d
- Module: 001caa38
- IsJitted: yes
- CodeAddr: 03ef00b8
- Source file: c:\Code\prj.mini\exc.cs @ 39
+ 0:000> K
+ ChildEBP RetAddr
+ 00a79c78 03ef02ab image00400000!Mainy.Top()+0xb
+ 00a79c78 03ef01a6 image00400000!Mainy.Level(Int32)+0xb
+ 00a79c78 5d3725a1 image00400000!Mainy.Main()+0xee
+ 0012ea04 5d512f59 clr!CallDescrWorkerInternal+0x30
+ 0012ee34 5d7946aa clr!CallDescrWorker+0x109
+
+ 0:000> !IP2MD 03ef01a6
+ MethodDesc: 00902f40
+ Method Name: Mainy.Main()
+ Class: 03ee1424
+ MethodTable: 009032d8
+ mdToken: 0600000d
+ Module: 001caa38
+ IsJitted: yes
+ CodeAddr: 03ef00b8
+ Source file: c:\Code\prj.mini\exc.cs @ 39
We have taken a return address into Mainy.Main, and discovered information
about that method. You could run !U, !DumpMT, !DumpClass, !DumpMD, or
debugger "U" function, the entire method from start to finish is printed,
with annotations that convert metadata tokens to names.
- <example output>
- ...
- 03ef015d b901000000 mov ecx,0x1
- 03ef0162 ff156477a25b call dword ptr [mscorlib_dll+0x3c7764 (5ba27764)] (System.Console.InitializeStdOutError(Boolean), mdToken: 06000713)
- 03ef0168 a17c20a701 mov eax,[01a7207c] (Object: SyncTextWriter)
- 03ef016d 89442414 mov [esp+0x14],eax
+ <example output>
+ ...
+ 03ef015d b901000000 mov ecx,0x1
+ 03ef0162 ff156477a25b call dword ptr [mscorlib_dll+0x3c7764 (5ba27764)] (System.Console.InitializeStdOutError(Boolean), mdToken: 06000713)
+ 03ef0168 a17c20a701 mov eax,[01a7207c] (Object: SyncTextWriter)
+ 03ef016d 89442414 mov [esp+0x14],eax
If you pass the -gcinfo flag, you'll get inline display of the GCInfo for
the method. You can also obtain this information with the !GCInfo command.
disassembly. The -n (No line numbers) flag can be specified to disable this
behavior.
- <example output>
- ...
- c:\Code\prj.mini\exc.cs @ 38:
- 001b00b0 8b0d3020ab03 mov ecx,dword ptr ds:[3AB2030h] ("Break in debugger. When done type <Enter> to continue: ")
- 001b00b6 e8d5355951 call mscorlib_ni+0x8b3690 (51743690) (System.Console.Write(System.String), mdToken: 0600091b)
- 001b00bb 90 nop
-
- c:\Code\prj.mini\exc.cs @ 39:
- 001b00bc e863cdc651 call mscorlib_ni+0xf8ce24 (51e1ce24) (System.Console.ReadLine(), mdToken: 060008f6)
- >>> 001b00c1 90 nop
- ...
+ <example output>
+ ...
+ c:\Code\prj.mini\exc.cs @ 38:
+ 001b00b0 8b0d3020ab03 mov ecx,dword ptr ds:[3AB2030h] ("Break in debugger. When done type <Enter> to continue: ")
+ 001b00b6 e8d5355951 call mscorlib_ni+0x8b3690 (51743690) (System.Console.Write(System.String), mdToken: 0600091b)
+ 001b00bb 90 nop
+
+ c:\Code\prj.mini\exc.cs @ 39:
+ 001b00bc e863cdc651 call mscorlib_ni+0xf8ce24 (51e1ce24) (System.Console.ReadLine(), mdToken: 060008f6)
+ >>> 001b00c1 90 nop
+ ...
\\
COMMAND: dumpstack.
Sample output:
- 0:000> !ehinfo 33bbd3a
- MethodDesc: 03310f68
- Method Name: MainClass.Main()
- Class: 03571358
- MethodTable: 0331121c
- mdToken: 0600000b
- Module: 001e2fd8
- IsJitted: yes
- CodeAddr: 033bbca0
+ 0:000> !ehinfo 33bbd3a
+ MethodDesc: 03310f68
+ Method Name: MainClass.Main()
+ Class: 03571358
+ MethodTable: 0331121c
+ mdToken: 0600000b
+ Module: 001e2fd8
+ IsJitted: yes
+ CodeAddr: 033bbca0
- EHHandler 0: TYPED catch(System.IO.FileNotFoundException)
- Clause: [033bbd2b, 033bbd3c] [8b, 9c]
- Handler: [033bbd3c, 033bbd50] [9c, b0]
+ EHHandler 0: TYPED catch(System.IO.FileNotFoundException)
+ Clause: [033bbd2b, 033bbd3c] [8b, 9c]
+ Handler: [033bbd3c, 033bbd50] [9c, b0]
- EHHandler 1: FINALLY
- Clause: [033bbd83, 033bbda3] [e3, 103]
- Handler: [033bbda3, 033bbdc5] [103, 125]
+ EHHandler 1: FINALLY
+ Clause: [033bbd83, 033bbda3] [e3, 103]
+ Handler: [033bbda3, 033bbdc5] [103, 125]
- EHHandler 2: TYPED catch(System.Exception)
- Clause: [033bbd7a, 033bbdc5] [da, 125]
- Handler: [033bbdc5, 033bbdd6] [125, 136]
+ EHHandler 2: TYPED catch(System.Exception)
+ Clause: [033bbd7a, 033bbdc5] [da, 125]
+ Handler: [033bbdc5, 033bbdd6] [125, 136]
\\
method. For example, the notation "reg EDI becoming live" at offset 0x11 of the
method might correspond to a "mov edi,ecx" statement.
- 0:000> !gcinfo 5b68dbb8 (5b68dbb8 is the start of a JITTED method)
- entry point 5b68dbb8
- preJIT generated code
- GC info 5b9f2f09
- Method info block:
- method size = 0036
- prolog size = 19
- epilog size = 8
- epilog count = 1
- epilog end = yes
- saved reg. mask = 000B
- ebp frame = yes
- fully interruptible=yes
- double align = no
- security check = no
- exception handlers = no
- local alloc = no
- edit & continue = no
- varargs = no
- argument count = 4
- stack frame size = 1
- untracked count = 5
- var ptr tab count = 0
- epilog at 002E
- 36 D4 8C C7 AA |
- 93 F3 40 05 |
-
- Pointer table:
- 14 | [EBP+14H] an untracked local
- 10 | [EBP+10H] an untracked local
- 0C | [EBP+0CH] an untracked local
- 08 | [EBP+08H] an untracked local
- 44 | [EBP-04H] an untracked local
- F1 79 | 0011 reg EDI becoming live
- 72 | 0013 reg ESI becoming live
- 83 | 0016 push ptr 0
- 8B | 0019 push ptr 1
- 93 | 001C push ptr 2
- 9B | 001F push ptr 3
- 56 | 0025 reg EDX becoming live
- 4A | 0027 reg ECX becoming live
- 0E | 002D reg ECX becoming dead
- 10 | 002D reg EDX becoming dead
- E0 | 002D pop 4 ptrs
- F0 31 | 0036 reg ESI becoming dead
- 38 | 0036 reg EDI becoming dead
- FF |
+ 0:000> !gcinfo 5b68dbb8 (5b68dbb8 is the start of a JITTED method)
+ entry point 5b68dbb8
+ preJIT generated code
+ GC info 5b9f2f09
+ Method info block:
+ method size = 0036
+ prolog size = 19
+ epilog size = 8
+ epilog count = 1
+ epilog end = yes
+ saved reg. mask = 000B
+ ebp frame = yes
+ fully interruptible=yes
+ double align = no
+ security check = no
+ exception handlers = no
+ local alloc = no
+ edit & continue = no
+ varargs = no
+ argument count = 4
+ stack frame size = 1
+ untracked count = 5
+ var ptr tab count = 0
+ epilog at 002E
+ 36 D4 8C C7 AA |
+ 93 F3 40 05 |
+
+ Pointer table:
+ 14 | [EBP+14H] an untracked local
+ 10 | [EBP+10H] an untracked local
+ 0C | [EBP+0CH] an untracked local
+ 08 | [EBP+08H] an untracked local
+ 44 | [EBP-04H] an untracked local
+ F1 79 | 0011 reg EDI becoming live
+ 72 | 0013 reg ESI becoming live
+ 83 | 0016 push ptr 0
+ 8B | 0019 push ptr 1
+ 93 | 001C push ptr 2
+ 9B | 001F push ptr 3
+ 56 | 0025 reg EDX becoming live
+ 4A | 0027 reg ECX becoming live
+ 0E | 002D reg ECX becoming dead
+ 10 | 002D reg EDX becoming dead
+ E0 | 002D pop 4 ptrs
+ F0 31 | 0036 reg ESI becoming dead
+ 38 | 0036 reg EDI becoming dead
+ FF |
This function is important for CLR Devs, but very difficult for anyone else to
make sense of it. You would usually come to use it if you suspect a gc heap
method name from the metadata, or from the output of the "!dumpmt -md" command.
For example:
- public interface I1
- {
- void M1();
- }
- public class ExplicitItfImpl : I1
- {
- ...
- void I1.M1() // this method's name is 'I1.M1'
- { ... }
- }
+ public interface I1
+ {
+ void M1();
+ }
+ public class ExplicitItfImpl : I1
+ {
+ ...
+ void I1.M1() // this method's name is 'I1.M1'
+ { ... }
+ }
- !bpmd myapp.exe ExplicitItfImpl.I1.M1
+ !bpmd myapp.exe ExplicitItfImpl.I1.M1
!bpmd works equally well with generic types. Adding a breakpoint on a generic
breakpoint for any instantiation that will be JIT-ted in the future.
Example for generics:
- Given the following two classes:
+ Given the following two classes:
- class G3<T1, T2, T3>
- {
- ...
- public void F(T1 p1, T2 p2, T3 p3)
- { ... }
- }
+ class G3<T1, T2, T3>
+ {
+ ...
+ public void F(T1 p1, T2 p2, T3 p3)
+ { ... }
+ }
- public class G1<T> {
- // static method
- static public void G<W>(W w)
- { ... }
- }
+ public class G1<T> {
+ // static method
+ static public void G<W>(W w)
+ { ... }
+ }
- One would issue the following commands to set breapoints on G3.F() and
- G1.G():
+ One would issue the following commands to set breapoints on G3.F() and
+ G1.G():
- !bpmd myapp.exe G3`3.F
- !bpmd myapp.exe G1`1.G
+ !bpmd myapp.exe G3`3.F
+ !bpmd myapp.exe G1`1.G
And for explicitly implemented methods on generic interfaces:
- public interface IT1<T>
- {
- void M1(T t);
- }
+ public interface IT1<T>
+ {
+ void M1(T t);
+ }
- public class ExplicitItfImpl<U> : IT1<U>
- {
- ...
- void IT1<U>.M1(U u) // this method's name is 'IT1<U>.M1'
- { ... }
- }
+ public class ExplicitItfImpl<U> : IT1<U>
+ {
+ ...
+ void IT1<U>.M1(U u) // this method's name is 'IT1<U>.M1'
+ { ... }
+ }
- !bpmd bpmd.exe ExplicitItfImpl`1.IT1<U>.M1
+ !bpmd bpmd.exe ExplicitItfImpl`1.IT1<U>.M1
Additional examples:
- If IT1 and ExplicitItfImpl are types declared inside another class,
- Outer, the bpmd command would become:
+ If IT1 and ExplicitItfImpl are types declared inside another class,
+ Outer, the bpmd command would become:
- !bpmd bpmd.exe Outer+ExplicitItfImpl`1.Outer.IT1<U>.M1
+ !bpmd bpmd.exe Outer+ExplicitItfImpl`1.Outer.IT1<U>.M1
- (note that the fully qualified type name for ExplicitItfImpl became
- Outer+ExplicitItfImpl, using the '+' separator, while the method name
- is Outer.IT1<U>.M1, using a '.' as the separator)
+ (note that the fully qualified type name for ExplicitItfImpl became
+ Outer+ExplicitItfImpl, using the '+' separator, while the method name
+ is Outer.IT1<U>.M1, using a '.' as the separator)
- Furthermore, if the Outer class resides in a namespace, NS, the bpmd
- command to use becomes:
+ Furthermore, if the Outer class resides in a namespace, NS, the bpmd
+ command to use becomes:
- !bpmd bpmd.exe NS.Outer+ExplicitItfImpl`1.NS.Outer.IT1<U>.M1
+ !bpmd bpmd.exe NS.Outer+ExplicitItfImpl`1.NS.Outer.IT1<U>.M1
!bpmd does not accept offsets nor parameters in the method name. You can add
an IL offset as an optional parameter seperate from the name. If there are overloaded
Here is output for a simple program:
- 0:000> !eeheap -gc
- Number of GC Heaps: 1
- generation 0 starts at 0x00a71018
- generation 1 starts at 0x00a7100c
- generation 2 starts at 0x00a71000
- segment begin allocated size
- 00a70000 00a71000 00a7e01c 0000d01c(53276)
- Large object heap starts at 0x01a71000
- segment begin allocated size
- 01a70000 01a71000 01a76000 0x00005000(20480)
- Total Size 0x1201c(73756)
- ------------------------------
- GC Heap Size 0x1201c(73756)
+ 0:000> !eeheap -gc
+ Number of GC Heaps: 1
+ generation 0 starts at 0x00a71018
+ generation 1 starts at 0x00a7100c
+ generation 2 starts at 0x00a71000
+ segment begin allocated size
+ 00a70000 00a71000 00a7e01c 0000d01c(53276)
+ Large object heap starts at 0x01a71000
+ segment begin allocated size
+ 01a70000 01a71000 01a76000 0x00005000(20480)
+ Total Size 0x1201c(73756)
+ ------------------------------
+ GC Heap Size 0x1201c(73756)
So the total size of the GC Heap is only 72K. On a large web server, with
multiple processors, you can expect to see a GC Heap of 400MB or more. The
also lists heaps associated with the JIT compiler, and heaps associated with
Modules. For example:
- 0:000> !EEHeap -loader
- Loader Heap:
- --------------------------------------
- System Domain: 5e0662a0
- LowFrequencyHeap:008f0000(00002000:00001000) Size: 0x00001000 bytes.
- HighFrequencyHeap:008f2000(00008000:00001000) Size: 0x00001000 bytes.
- StubHeap:008fa000(00002000:00001000) Size: 0x00001000 bytes.
- Total size: 0x3000(12288)bytes
- --------------------------------------
- Shared Domain: 5e066970
- LowFrequencyHeap:00920000(00002000:00001000) 03e30000(00010000:00003000) Size: 0x00004000 bytes.
- Wasted: 0x00001000 bytes.
- HighFrequencyHeap:00922000(00008000:00001000) Size: 0x00001000 bytes.
- StubHeap:0092a000(00002000:00001000) Size: 0x00001000 bytes.
- Total size: 0x6000(24576)bytes
- --------------------------------------
- Domain 1: 14f000
- LowFrequencyHeap:00900000(00002000:00001000) 03ee0000(00010000:00003000) Size: 0x00004000 bytes.
- Wasted: 0x00001000 bytes.
- HighFrequencyHeap:00902000(00008000:00003000) Size: 0x00003000 bytes.
- StubHeap:0090a000(00002000:00001000) Size: 0x00001000 bytes.
- Total size: 0x8000(32768)bytes
- --------------------------------------
- Jit code heap:
- Normal JIT:03ef0000(00010000:00002000) Size: 0x00002000 bytes.
- Total size: 0x2000(8192)bytes
- --------------------------------------
- Module Thunk heaps:
- Module 5ba22410: Size: 0x00000000 bytes.
- Module 001c1320: Size: 0x00000000 bytes.
- Module 001c03f0: Size: 0x00000000 bytes.
- Module 001caa38: Size: 0x00000000 bytes.
- Total size: 0x0(0)bytes
- --------------------------------------
- Module Lookup Table heaps:
- Module 5ba22410:Size: 0x00000000 bytes.
- Module 001c1320:Size: 0x00000000 bytes.
- Module 001c03f0:Size: 0x00000000 bytes.
- Module 001caa38:03ec0000(00010000:00002000) Size: 0x00002000 bytes.
- Total size: 0x2000(8192)bytes
- --------------------------------------
- Total LoaderHeap size: 0x15000(86016)bytes
- =======================================
+ 0:000> !EEHeap -loader
+ Loader Heap:
+ --------------------------------------
+ System Domain: 5e0662a0
+ LowFrequencyHeap:008f0000(00002000:00001000) Size: 0x00001000 bytes.
+ HighFrequencyHeap:008f2000(00008000:00001000) Size: 0x00001000 bytes.
+ StubHeap:008fa000(00002000:00001000) Size: 0x00001000 bytes.
+ Total size: 0x3000(12288)bytes
+ --------------------------------------
+ Shared Domain: 5e066970
+ LowFrequencyHeap:00920000(00002000:00001000) 03e30000(00010000:00003000) Size: 0x00004000 bytes.
+ Wasted: 0x00001000 bytes.
+ HighFrequencyHeap:00922000(00008000:00001000) Size: 0x00001000 bytes.
+ StubHeap:0092a000(00002000:00001000) Size: 0x00001000 bytes.
+ Total size: 0x6000(24576)bytes
+ --------------------------------------
+ Domain 1: 14f000
+ LowFrequencyHeap:00900000(00002000:00001000) 03ee0000(00010000:00003000) Size: 0x00004000 bytes.
+ Wasted: 0x00001000 bytes.
+ HighFrequencyHeap:00902000(00008000:00003000) Size: 0x00003000 bytes.
+ StubHeap:0090a000(00002000:00001000) Size: 0x00001000 bytes.
+ Total size: 0x8000(32768)bytes
+ --------------------------------------
+ Jit code heap:
+ Normal JIT:03ef0000(00010000:00002000) Size: 0x00002000 bytes.
+ Total size: 0x2000(8192)bytes
+ --------------------------------------
+ Module Thunk heaps:
+ Module 5ba22410: Size: 0x00000000 bytes.
+ Module 001c1320: Size: 0x00000000 bytes.
+ Module 001c03f0: Size: 0x00000000 bytes.
+ Module 001caa38: Size: 0x00000000 bytes.
+ Total size: 0x0(0)bytes
+ --------------------------------------
+ Module Lookup Table heaps:
+ Module 5ba22410:Size: 0x00000000 bytes.
+ Module 001c1320:Size: 0x00000000 bytes.
+ Module 001c03f0:Size: 0x00000000 bytes.
+ Module 001caa38:03ec0000(00010000:00002000) Size: 0x00002000 bytes.
+ Total size: 0x2000(8192)bytes
+ --------------------------------------
+ Total LoaderHeap size: 0x15000(86016)bytes
+ =======================================
By using !EEHeap to keep track of the growth of these private heaps, we are
able to rule out or include them as a source of a memory leak.
This function allows you to turn a class name into a MethodTable and EEClass.
It turns a method name into a MethodDesc. Here is an example for a method:
- 0:000> !name2ee unittest.exe MainClass.Main
- Module: 001caa38
- Token: 0x0600000d
- MethodDesc: 00902f40
- Name: MainClass.Main()
- JITTED Code Address: 03ef00b8
+ 0:000> !name2ee unittest.exe MainClass.Main
+ Module: 001caa38
+ Token: 0x0600000d
+ MethodDesc: 00902f40
+ Name: MainClass.Main()
+ JITTED Code Address: 03ef00b8
and for a class:
- 0:000> !name2ee unittest!MainClass
- Module: 001caa38
- Token: 0x02000005
- MethodTable: 009032d8
- EEClass: 03ee1424
- Name: MainClass
+ 0:000> !name2ee unittest!MainClass
+ Module: 001caa38
+ Token: 0x02000005
+ MethodTable: 009032d8
+ EEClass: 03ee1424
+ Name: MainClass
The module you are "browsing" with Name2EE needs to be loaded in the process.
To get a type name exactly right, first browse the module with ILDASM. You
For this kind of module, simply use price as the module name:
- 0:044> !name2ee price Price
- Module: 10f028b0 (price, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)
- Token: 0x02000002
- MethodTable: 11a47ae0
- EEClass: 11a538c8
- Name: Price
+ 0:044> !name2ee price Price
+ Module: 10f028b0 (price, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)
+ Token: 0x02000002
+ MethodTable: 11a47ae0
+ EEClass: 11a538c8
+ Name: Price
Where are we getting these module names from? Run !DumpDomain to see a list of
all loaded modules in all domains. And remember that you can browse all the
leaving both threads with no option but to wait forever in the second lock
statement. !SyncBlk will detect this with the following output:
- 0:003> !syncblk
- Index SyncBlock MonitorHeld Recursion Owning Thread Info SyncBlock Owner
- 238 001e40ec 3 1 001e4e60 e04 3 00a7a194 Resource
- 239 001e4124 3 1 001e5980 ab8 4 00a7a1a4 Resource
+ 0:003> !syncblk
+ Index SyncBlock MonitorHeld Recursion Owning Thread Info SyncBlock Owner
+ 238 001e40ec 3 1 001e4e60 e04 3 00a7a194 Resource
+ 239 001e4124 3 1 001e5980 ab8 4 00a7a1a4 Resource
It means that Thread e04 owns object 00a7a194, and Thread ab8 owns object
00a7a1a4. Combine that information with the call stacks of the deadlock:
(threads 3 and 4 have similar output)
- 0:003> k
- ChildEBP RetAddr
- 0404ea04 77f5c524 SharedUserData!SystemCallStub+0x4
- 0404ea08 77e75ee0 ntdll!NtWaitForMultipleObjects+0xc
- 0404eaa4 5d9de9d6 KERNEL32!WaitForMultipleObjectsEx+0x12c
- 0404eb38 5d9def80 clr!Thread::DoAppropriateAptStateWait+0x156
- 0404ecc4 5d9dd8bb clr!Thread::DoAppropriateWaitWorker+0x360
- 0404ed20 5da628dd clr!Thread::DoAppropriateWait+0xbb
- 0404ede4 5da4e2e2 clr!CLREvent::Wait+0x29d
- 0404ee70 5da4dd41 clr!AwareLock::EnterEpilog+0x132
- 0404ef34 5da4efa3 clr!AwareLock::Enter+0x2c1
- 0404f09c 5d767880 clr!AwareLock::Contention+0x483
- 0404f1c4 03f00229 clr!JITutil_MonContention+0x2c0
- 0404f1f4 5b6ef077 image00400000!Worker.Work()+0x79
- ...
+ 0:003> k
+ ChildEBP RetAddr
+ 0404ea04 77f5c524 SharedUserData!SystemCallStub+0x4
+ 0404ea08 77e75ee0 ntdll!NtWaitForMultipleObjects+0xc
+ 0404eaa4 5d9de9d6 KERNEL32!WaitForMultipleObjectsEx+0x12c
+ 0404eb38 5d9def80 clr!Thread::DoAppropriateAptStateWait+0x156
+ 0404ecc4 5d9dd8bb clr!Thread::DoAppropriateWaitWorker+0x360
+ 0404ed20 5da628dd clr!Thread::DoAppropriateWait+0xbb
+ 0404ede4 5da4e2e2 clr!CLREvent::Wait+0x29d
+ 0404ee70 5da4dd41 clr!AwareLock::EnterEpilog+0x132
+ 0404ef34 5da4efa3 clr!AwareLock::Enter+0x2c1
+ 0404f09c 5d767880 clr!AwareLock::Contention+0x483
+ 0404f1c4 03f00229 clr!JITutil_MonContention+0x2c0
+ 0404f1f4 5b6ef077 image00400000!Worker.Work()+0x79
+ ...
By looking at the code corresponding to Worker.Work()+0x79 (run "!u 03f00229"),
you can see that thread 3 is attempting to acquire the Resource 00a7a1a4, which
This command lists information about a MethodDesc. You can use !IP2MD to turn
a code address in a managed function into a MethodDesc:
- 0:000> !dumpmd 902f40
- Method Name: Mainy.Main()
- Class: 03ee1424
- MethodTable: 009032d8
- mdToken: 0600000d
- Module: 001caa78
- IsJitted: yes
- CodeAddr: 03ef00b8
+ 0:000> !dumpmd 902f40
+ Method Name: Mainy.Main()
+ Class: 03ee1424
+ MethodTable: 009032d8
+ mdToken: 0600000d
+ Module: 001caa78
+ IsJitted: yes
+ CodeAddr: 03ef00b8
If IsJitted is "yes," you can run !U on the CodeAddr pointer to see a
disassembly of the JITTED code. You can also call !DumpClass, !DumpMT,
This function allows you to turn a metadata token into a MethodTable or
MethodDesc. Here is an example showing class tokens being resolved:
- 0:000> !token2ee unittest.exe 02000003
- Module: 001caa38
- Token: 0x02000003
- MethodTable: 0090375c
- EEClass: 03ee1ae0
- Name: Bank
- 0:000> !token2ee image00400000 02000004
- Module: 001caa38
- Token: 0x02000004
- MethodTable: 009038ec
- EEClass: 03ee1b84
- Name: Customer
+ 0:000> !token2ee unittest.exe 02000003
+ Module: 001caa38
+ Token: 0x02000003
+ MethodTable: 0090375c
+ EEClass: 03ee1ae0
+ Name: Bank
+ 0:000> !token2ee image00400000 02000004
+ Module: 001caa38
+ Token: 0x02000004
+ MethodTable: 009038ec
+ EEClass: 03ee1b84
+ Name: Customer
The module you are "browsing" with Token2EE needs to be loaded in the process.
This function doesn't see much use, especially since a tool like ILDASM can
You can get a Module address from !DumpDomain, !DumpAssembly and other
functions. Here is sample output:
- 0:000> !DumpModule 1caa50
- Name: C:\pub\unittest.exe
- Attributes: PEFile
- Assembly: 001ca248
- LoaderHeap: 001cab3c
- TypeDefToMethodTableMap: 03ec0010
- TypeRefToMethodTableMap: 03ec0024
- MethodDefToDescMap: 03ec0064
- FieldDefToDescMap: 03ec00a4
- MemberRefToDescMap: 03ec00e8
- FileReferencesMap: 03ec0128
- AssemblyReferencesMap: 03ec012c
- MetaData start address: 00402230 (1888 bytes)
+ 0:000> !DumpModule 1caa50
+ Name: C:\pub\unittest.exe
+ Attributes: PEFile
+ Assembly: 001ca248
+ LoaderHeap: 001cab3c
+ TypeDefToMethodTableMap: 03ec0010
+ TypeRefToMethodTableMap: 03ec0024
+ MethodDefToDescMap: 03ec0064
+ FieldDefToDescMap: 03ec00a4
+ MemberRefToDescMap: 03ec00e8
+ FileReferencesMap: 03ec0128
+ AssemblyReferencesMap: 03ec012c
+ MetaData start address: 00402230 (1888 bytes)
The Maps listed map metadata tokens to CLR data structures. Without going into
too much detail, you can examine memory at those addresses to find the
appropriate structures. For example, the TypeDefToMethodTableMap above can be
examined:
- 0:000> dd 3ec0010
- 03ec0010 00000000 00000000 0090320c 0090375c
- 03ec0020 009038ec ...
+ 0:000> dd 3ec0010
+ 03ec0010 00000000 00000000 0090320c 0090375c
+ 03ec0020 009038ec ...
This means TypeDef token 2 maps to a MethodTable with the value 0090320c. You
can run !DumpMT to verify that. The MethodDefToDescMap takes a MethodDef token
There is a new option "-mt", which will display the types defined in a module,
and the types referenced by the module. For example:
- 0:000> !dumpmodule -mt 1aa580
- Name: C:\pub\unittest.exe
- ...<etc>...
- MetaData start address: 0040220c (1696 bytes)
+ 0:000> !dumpmodule -mt 1aa580
+ Name: C:\pub\unittest.exe
+ ...<etc>...
+ MetaData start address: 0040220c (1696 bytes)
- Types defined in this module
+ Types defined in this module
- MT TypeDef Name
- --------------------------------------------------------------------------
- 030d115c 0x02000002 Funny
- 030d1228 0x02000003 Mainy
+ MT TypeDef Name
+ --------------------------------------------------------------------------
+ 030d115c 0x02000002 Funny
+ 030d1228 0x02000003 Mainy
- Types referenced in this module
+ Types referenced in this module
- MT TypeRef Name
- --------------------------------------------------------------------------
- 030b6420 0x01000001 System.ValueType
- 030b5cb0 0x01000002 System.Object
- 030fceb4 0x01000003 System.Exception
- 0334e374 0x0100000c System.Console
- 03167a50 0x0100000e System.Runtime.InteropServices.GCHandle
- 0336a048 0x0100000f System.GC
+ MT TypeRef Name
+ --------------------------------------------------------------------------
+ 030b6420 0x01000001 System.ValueType
+ 030b5cb0 0x01000002 System.Object
+ 030fceb4 0x01000003 System.Exception
+ 0334e374 0x0100000c System.Console
+ 03167a50 0x0100000e System.Runtime.InteropServices.GCHandle
+ 0336a048 0x0100000f System.GC
\\
Example output:
- 0:000> !dumpassembly 1ca248
- Parent Domain: 0014f000
- Name: C:\pub\unittest.exe
- ClassLoader: 001ca060
- Module Name
- 001caa50 C:\pub\unittest.exe
+ 0:000> !dumpassembly 1ca248
+ Parent Domain: 0014f000
+ Name: C:\pub\unittest.exe
+ ClassLoader: 001ca060
+ Module Name
+ 001caa50 C:\pub\unittest.exe
An assembly can consist of multiple modules, and those will be listed. You can
get an Assembly address from the output of !DumpDomain.
!DumpRuntimeTypes finds all System.RuntimeType objects in the gc heap and
prints the type name and MethodTable they refer too. Sample output:
- Address Domain MT Type Name
- ------------------------------------------------------------------------------
- a515f4 14a740 5baf8d28 System.TypedReference
- a51608 14a740 5bb05764 System.Globalization.BaseInfoTable
- a51958 14a740 5bb05b24 System.Globalization.CultureInfo
- a51a44 14a740 5bb06298 System.Globalization.GlobalizationAssembly
- a51de0 14a740 5bb069c8 System.Globalization.TextInfo
- a56b98 14a740 5bb12d28 System.Security.Permissions.HostProtectionResource
- a56bbc 14a740 5baf7248 System.Int32
- a56bd0 14a740 5baf3fdc System.String
- a56cfc 14a740 5baf36a4 System.ValueType
- ...
+ Address Domain MT Type Name
+ ------------------------------------------------------------------------------
+ a515f4 14a740 5baf8d28 System.TypedReference
+ a51608 14a740 5bb05764 System.Globalization.BaseInfoTable
+ a51958 14a740 5bb05b24 System.Globalization.CultureInfo
+ a51a44 14a740 5bb06298 System.Globalization.GlobalizationAssembly
+ a51de0 14a740 5bb069c8 System.Globalization.TextInfo
+ a56b98 14a740 5bb12d28 System.Security.Permissions.HostProtectionResource
+ a56bbc 14a740 5baf7248 System.Int32
+ a56bd0 14a740 5baf3fdc System.String
+ a56cfc 14a740 5baf36a4 System.ValueType
+ ...
This command will print a "?" in the domain column if the type is loaded into multiple
AppDomains. For example:
If an error is found, !VerifyHeap will report it. I'll take a perfectly good
object and corrupt it:
- 0:000> !DumpObj a79d40
- Name: Customer
- MethodTable: 009038ec
- EEClass: 03ee1b84
- Size: 20(0x14) bytes
- (C:\pub\unittest.exe)
- Fields:
- MT Field Offset Type Attr Value Name
- 009038ec 4000008 4 CLASS instance 00a79ce4 name
- 009038ec 4000009 8 CLASS instance 00a79d2c bank
- 009038ec 400000a c System.Boolean instance 1 valid
-
- 0:000> ed a79d40+4 01 (change the name field to the bogus pointer value 1)
- 0:000> !VerifyHeap
- object 01ee60dc: bad member 00000003 at 01EE6168
- Last good object: 01EE60C4.
+ 0:000> !DumpObj a79d40
+ Name: Customer
+ MethodTable: 009038ec
+ EEClass: 03ee1b84
+ Size: 20(0x14) bytes
+ (C:\pub\unittest.exe)
+ Fields:
+ MT Field Offset Type Attr Value Name
+ 009038ec 4000008 4 CLASS instance 00a79ce4 name
+ 009038ec 4000009 8 CLASS instance 00a79d2c bank
+ 009038ec 400000a c System.Boolean instance 1 valid
+
+ 0:000> ed a79d40+4 01 (change the name field to the bogus pointer value 1)
+ 0:000> !VerifyHeap
+ object 01ee60dc: bad member 00000003 at 01EE6168
+ Last good object: 01EE60C4.
If this gc heap corruption exists, there is a serious bug in your own code or
in the CLR. In user code, an error in constructing PInvoke calls can cause
!VerifyObj is a diagnostic tool that checks the object that is passed as an
argument for signs of corruption.
- 0:002> !verifyobj 028000ec
- object 0x28000ec does not have valid method table
+ 0:002> !verifyobj 028000ec
+ object 0x28000ec does not have valid method table
- 0:002> !verifyobj 0680017c
- object 0x680017c: bad member 00000001 at 06800184
+ 0:002> !verifyobj 0680017c
+ object 0x680017c: bad member 00000001 at 06800184
\\
1. Find out the generation of the object of interest using the !GCWhere
command, say it is gen 1:
- !GCWhere <object address>
+ !GCWhere <object address>
2. Instruct the runtime to stop the next time it collects that generation using
the !FindRoots command:
- !FindRoots -gen 1
- g
+ !FindRoots -gen 1
+ g
3. When the next GC starts, and has proceeded past the mark phase a CLR
notification will cause a break in the debugger:
- (fd0.ec4): CLR notification exception - code e0444143 (first chance)
- CLR notification: GC - end of mark phase.
- Condemned generation: 1.
+ (fd0.ec4): CLR notification exception - code e0444143 (first chance)
+ CLR notification: GC - end of mark phase.
+ Condemned generation: 1.
4. Now we can use the !FindRoots <object address> to find out the cross
generational references to the object of interest. In other words, even if the
older object (from an older generation), from a generation that has not yet been
scheduled for collection. At this point !FindRoots will search those older
generations too, and report those roots.
- 0:002> !findroots 06808094
- older generations::Root: 068012f8(AAA.Test+a)->
- 06808094(AAA.Test+b)
+ 0:002> !findroots 06808094
+ older generations::Root: 068012f8(AAA.Test+a)->
+ 06808094(AAA.Test+b)
\\
Sample output:
- 0:002> !heapstat
- Heap Gen0 Gen1 Gen2 LOH
- Heap0 177904 12 306956 8784
- Heap1 159652 12 12 16
- Total 337556 24 306968 8800
-
- Free space: Percentage
- Heap0 28 12 12 64 SOH: 0%% LOH: 0%%
- Heap1 104 12 12 16 SOH: 0%% LOH:100%%
- Total 132 24 24 80
-
- 0:002> !heapstat -inclUnrooted
- Heap Gen0 Gen1 Gen2 LOH
- Heap0 177904 12 306956 8784
- Heap1 159652 12 12 16
- Total 337556 24 306968 8800
-
- Free space: Percentage
- Heap0 28 12 12 64 SOH: 0%% LOH: 0%%
- Heap1 104 12 12 16 SOH: 0%% LOH:100%%
- Total 132 24 24 80
-
- Unrooted objects: Percentage
- Heap0 152212 0 306196 0 SOH: 94%% LOH: 0%%
- Heap1 155704 0 0 0 SOH: 97%% LOH: 0%%
- Total 307916 0 306196 0
+ 0:002> !heapstat
+ Heap Gen0 Gen1 Gen2 LOH
+ Heap0 177904 12 306956 8784
+ Heap1 159652 12 12 16
+ Total 337556 24 306968 8800
+
+ Free space: Percentage
+ Heap0 28 12 12 64 SOH: 0%% LOH: 0%%
+ Heap1 104 12 12 16 SOH: 0%% LOH:100%%
+ Total 132 24 24 80
+
+ 0:002> !heapstat -inclUnrooted
+ Heap Gen0 Gen1 Gen2 LOH
+ Heap0 177904 12 306956 8784
+ Heap1 159652 12 12 16
+ Total 337556 24 306968 8800
+
+ Free space: Percentage
+ Heap0 28 12 12 64 SOH: 0%% LOH: 0%%
+ Heap1 104 12 12 16 SOH: 0%% LOH:100%%
+ Total 132 24 24 80
+
+ Unrooted objects: Percentage
+ Heap0 152212 0 306196 0 SOH: 94%% LOH: 0%%
+ Heap1 155704 0 0 0 SOH: 97%% LOH: 0%%
+ Total 307916 0 306196 0
The percentage column contains a breakout of free or unrooted bytes to total bytes.
!GCWhere displays the location in the GC heap of the argument passed in.
- 0:002> !GCWhere 02800038
- Address Gen Heap segment begin allocated size
- 02800038 2 0 02800000 02800038 0282b740 12
+ 0:002> !GCWhere 02800038
+ Address Gen Heap segment begin allocated size
+ 02800038 2 0 02800000 02800038 0282b740 12
When the argument lies in the managed heap, but is not a valid *object* address
the "size" is displayed as 0:
- 0:002> !GCWhere 0280003c
- Address Gen Heap segment begin allocated size
- 0280003c 2 0 02800000 02800038 0282b740 0
+ 0:002> !GCWhere 0280003c
+ Address Gen Heap segment begin allocated size
+ 0280003c 2 0 02800000 02800038 0282b740 0
\\
beginning of a managed object (based on a valid method table) and the object
following the argument address.
- 0:002> !ListNearObj 028000ec
- Before: 0x28000a4 72 (0x48 ) System.StackOverflowException
- After: 0x2800134 72 (0x48 ) System.Threading.ThreadAbortException
- Heap local consistency confirmed.
+ 0:002> !ListNearObj 028000ec
+ Before: 0x28000a4 72 (0x48 ) System.StackOverflowException
+ After: 0x2800134 72 (0x48 ) System.Threading.ThreadAbortException
+ Heap local consistency confirmed.
- 0:002> !ListNearObj 028000f0
- Before: 0x28000ec 72 (0x48 ) System.ExecutionEngineException
- After: 0x2800134 72 (0x48 ) System.Threading.ThreadAbortException
- Heap local consistency confirmed.
+ 0:002> !ListNearObj 028000f0
+ Before: 0x28000ec 72 (0x48 ) System.ExecutionEngineException
+ After: 0x2800134 72 (0x48 ) System.Threading.ThreadAbortException
+ Heap local consistency confirmed.
The command considers the heap as "locally consistent" if:
- prev_obj_addr + prev_obj_size = arg_addr && arg_obj + arg_size = next_obj_addr
+ prev_obj_addr + prev_obj_size = arg_addr && arg_obj + arg_size = next_obj_addr
OR
- prev_obj_addr + prev_obj_size = next_obj_addr
+ prev_obj_addr + prev_obj_size = next_obj_addr
When the condition is not satisfied:
- 0:002> !lno 028000ec
- Before: 0x28000a4 72 (0x48 ) System.StackOverflowException
- After: 0x2800134 72 (0x48 ) System.Threading.ThreadAbortException
- Heap local consistency not confirmed.
+ 0:002> !lno 028000ec
+ Before: 0x28000a4 72 (0x48 ) System.StackOverflowException
+ After: 0x2800134 72 (0x48 ) System.Threading.ThreadAbortException
+ Heap local consistency not confirmed.
\\
The optional argument addr allows one to specify a stress log other then the
default one.
- 0:000> !DumpLog
- Attempting to dump Stress log to file 'StressLog.txt'
- .................
- SUCCESS: Stress log dumped
+ 0:000> !DumpLog
+ Attempting to dump Stress log to file 'StressLog.txt'
+ .................
+ SUCCESS: Stress log dumped
To turn on the stress log, set the following environment variables before
starting the .NET Core app:
Here is some sample output:
- 3560 9.981137099 : `SYNC` RareEnablePremptiveGC: entering.
- Thread state = a030
+ 3560 9.981137099 : `SYNC` RareEnablePremptiveGC: entering.
+ Thread state = a030
- 3560 9.981135033 : `GC`GCALLOC`GCROOTS` ========== ENDGC 4194 (gen = 2,
- collect_classes = 0) ==========={
+ 3560 9.981135033 : `GC`GCALLOC`GCROOTS` ========== ENDGC 4194 (gen = 2,
+ collect_classes = 0) ==========={
- 3560 9.981125826 : `GC` Segment mem 00C61000 alloc
- = 00D071F0 used 00D09254 committed 00D17000
+ 3560 9.981125826 : `GC` Segment mem 00C61000 alloc
+ = 00D071F0 used 00D09254 committed 00D17000
- 3560 9.981125726 : `GC` Generation 0 [00CED07C, 00000000
- ] cur = 00000000
+ 3560 9.981125726 : `GC` Generation 0 [00CED07C, 00000000
+ ] cur = 00000000
- 3560 9.981125529 : `GC` Generation 1 [00CED070, 00000000
- ] cur = 00000000
+ 3560 9.981125529 : `GC` Generation 1 [00CED070, 00000000
+ ] cur = 00000000
- 3560 9.981125103 : `GC` Generation 2 [00C61000, 00000000
- ] cur = 00000000
+ 3560 9.981125103 : `GC` Generation 2 [00C61000, 00000000
+ ] cur = 00000000
- 3560 9.981124963 : `GC` GC Heap 00000000
+ 3560 9.981124963 : `GC` GC Heap 00000000
- 3560 9.980618994 : `GC`GCROOTS` GcScanHandles (Promotion Phase = 0)
+ 3560 9.980618994 : `GC`GCROOTS` GcScanHandles (Promotion Phase = 0)
The first column is the OS thread ID for the thread appending to the log,
the second column is the timestamp, the third is the facility category for the
!FindAppDomain will attempt to resolve the AppDomain of an object. For example,
using an Object Pointer from the output of !DumpStackObjects:
- 0:000> !findappdomain 00a79d98
- AppDomain: 0014f000
- Name: unittest.exe
- ID: 1
+ 0:000> !findappdomain 00a79d98
+ AppDomain: 0014f000
+ Name: unittest.exe
+ ID: 1
You can find out more about the AppDomain with the !DumpDomain command. Not
every object has enough clues about it's origin to determine the AppDomain.
The base address of an image can be found with the "LM" debugger command:
- 0:000> lm
- start end module name
- 00400000 00408000 image00400000 (deferred)
- 10200000 102ac000 MSVCR80D (deferred)
- 5a000000 5a0b1000 mscoree (deferred)
- 5a140000 5a29e000 clrjit (deferred)
- 5b660000 5c440000 mscorlib_dll (deferred)
- 5d1d0000 5e13c000 clr (deferred)
- ...
+ 0:000> lm
+ start end module name
+ 00400000 00408000 image00400000 (deferred)
+ 10200000 102ac000 MSVCR80D (deferred)
+ 5a000000 5a0b1000 mscoree (deferred)
+ 5a140000 5a29e000 clrjit (deferred)
+ 5b660000 5c440000 mscorlib_dll (deferred)
+ 5d1d0000 5e13c000 clr (deferred)
+ ...
If I wanted to save a copy of coreclr.dll, I could run:
- 0:000> !SaveModule 5d1d0000 c:\pub\out.tmp
- 4 sections in file
- section 0 - VA=1000, VASize=e82da9, FileAddr=400, FileSize=e82e00
- section 1 - VA=e84000, VASize=24d24, FileAddr=e83200, FileSize=ec00
- section 2 - VA=ea9000, VASize=5a8, FileAddr=e91e00, FileSize=600
- section 3 - VA=eaa000, VASize=c183c, FileAddr=e92400, FileSize=c1a00
+ 0:000> !SaveModule 5d1d0000 c:\pub\out.tmp
+ 4 sections in file
+ section 0 - VA=1000, VASize=e82da9, FileAddr=400, FileSize=e82e00
+ section 1 - VA=e84000, VASize=24d24, FileAddr=e83200, FileSize=ec00
+ section 2 - VA=ea9000, VASize=5a8, FileAddr=e91e00, FileSize=600
+ section 3 - VA=eaa000, VASize=c183c, FileAddr=e92400, FileSize=c1a00
The diagnostic output indicates that the operation was successful. If
c:\pub\out.tmp already exists, it will be overwritten.
!VMMap traverses the virtual address space and lists the type of protection
applied to each region. Sample output:
- 0:000> !VMMap
- Start Stop Length AllocProtect Protect State Type
- 00000000-0000ffff 00010000 NA Free
- 00010000-00011fff 00002000 RdWr RdWr Commit Private
- 00012000-0001ffff 0000e000 NA Free
- 00020000-00020fff 00001000 RdWr RdWr Commit Private
- 00021000-0002ffff 0000f000 NA Free
- 00030000-00030fff 00001000 RdWr Reserve Private
- ...
+ 0:000> !VMMap
+ Start Stop Length AllocProtect Protect State Type
+ 00000000-0000ffff 00010000 NA Free
+ 00010000-00011fff 00002000 RdWr RdWr Commit Private
+ 00012000-0001ffff 0000e000 NA Free
+ 00020000-00020fff 00001000 RdWr RdWr Commit Private
+ 00021000-0002ffff 0000f000 NA Free
+ 00030000-00030fff 00001000 RdWr Reserve Private
+ ...
\\
COMMAND: vmstat.
protection applied to that memory (free, reserved, committed, private, mapped,
image). The TOTAL column is (AVERAGE * BLK COUNT). Sample output below:
- 0:000> !VMStat
- ~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~~~ ~~~~~
- TYPE MINIMUM MAXIMUM AVERAGE BLK COUNT TOTAL
- Free:
- Small 4,096 65,536 48,393 27 1,306,611
- Medium 139,264 528,384 337,920 4 1,351,680
- Large 6,303,744 974,778,368 169,089,706 12 2,029,076,472
- Summary 4,096 974,778,368 47,249,646 43 2,031,734,778
+ 0:000> !VMStat
+ ~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~~~ ~~~~~
+ TYPE MINIMUM MAXIMUM AVERAGE BLK COUNT TOTAL
+ Free:
+ Small 4,096 65,536 48,393 27 1,306,611
+ Medium 139,264 528,384 337,920 4 1,351,680
+ Large 6,303,744 974,778,368 169,089,706 12 2,029,076,472
+ Summary 4,096 974,778,368 47,249,646 43 2,031,734,778
- Reserve:
- Small 4,096 65,536 43,957 41 1,802,237
- Medium 249,856 1,019,904 521,557 6 3,129,342
- Large 2,461,696 16,703,488 11,956,224 3 35,868,672
- Summary 4,096 16,703,488 816,005 50 40,800,250
+ Reserve:
+ Small 4,096 65,536 43,957 41 1,802,237
+ Medium 249,856 1,019,904 521,557 6 3,129,342
+ Large 2,461,696 16,703,488 11,956,224 3 35,868,672
+ Summary 4,096 16,703,488 816,005 50 40,800,250
\\
Sample output:
- 0:001> !HistInit
- Attempting to read Stress log
- STRESS LOG:
- facilitiesToLog = 0xffffffff
- levelToLog = 6
- MaxLogSizePerThread = 0x10000 (65536)
- MaxTotalLogSize = 0x1000000 (16777216)
- CurrentTotalLogChunk = 9
- ThreadsWithLogs = 3
- Clock frequency = 3.392 GHz
- Start time 15:26:31
- Last message time 15:26:56
- Total elapsed time 25.077 sec
- .....................................
- ---------------------------- 2407 total entries -----------------------------
+ 0:001> !HistInit
+ Attempting to read Stress log
+ STRESS LOG:
+ facilitiesToLog = 0xffffffff
+ levelToLog = 6
+ MaxLogSizePerThread = 0x10000 (65536)
+ MaxTotalLogSize = 0x1000000 (16777216)
+ CurrentTotalLogChunk = 9
+ ThreadsWithLogs = 3
+ Clock frequency = 3.392 GHz
+ Start time 15:26:31
+ Last message time 15:26:56
+ Total elapsed time 25.077 sec
+ .....................................
+ ---------------------------- 2407 total entries -----------------------------
- SUCCESS: GCHist structures initialized
+ SUCCESS: GCHist structures initialized
\\
would use this command. The output of this command contains all entries that
reference the object:
- 0:003> !HistObjFind 028970d4
- GCCount Object Message
- ---------------------------------------------------------
- 2296 028970d4 Promotion for root 01e411b8 (MT = 5b6c5cd8)
- 2296 028970d4 Relocation NEWVALUE for root 00223fc4
- 2296 028970d4 Relocation NEWVALUE for root 01e411b8
- ...
- 2295 028970d4 Promotion for root 01e411b8 (MT = 5b6c5cd8)
- 2295 028970d4 Relocation NEWVALUE for root 00223fc4
- 2295 028970d4 Relocation NEWVALUE for root 01e411b8
- ...
+ 0:003> !HistObjFind 028970d4
+ GCCount Object Message
+ ---------------------------------------------------------
+ 2296 028970d4 Promotion for root 01e411b8 (MT = 5b6c5cd8)
+ 2296 028970d4 Relocation NEWVALUE for root 00223fc4
+ 2296 028970d4 Relocation NEWVALUE for root 01e411b8
+ ...
+ 2295 028970d4 Promotion for root 01e411b8 (MT = 5b6c5cd8)
+ 2295 028970d4 Relocation NEWVALUE for root 00223fc4
+ 2295 028970d4 Relocation NEWVALUE for root 01e411b8
+ ...
\\
HistRoot provides information related to both promotions and relocations of the
root specified as the argument.
- 0:003> !HistRoot 01e411b8
- GCCount Value MT Promoted? Notes
- ---------------------------------------------------------
- 2296 028970d4 5b6c5cd8 yes
- 2295 028970d4 5b6c5cd8 yes
- 2294 028970d4 5b6c5cd8 yes
- 2293 028970d4 5b6c5cd8 yes
- 2292 028970d4 5b6c5cd8 yes
- 2291 028970d4 5b6c5cd8 yes
- 2290 028970d4 5b6c5cd8 yes
- 2289 028970d4 5b6c5cd8 yes
- 2288 028970d4 5b6c5cd8 yes
- 2287 028970d4 5b6c5cd8 yes
- 2286 028970d4 5b6c5cd8 yes
- 2285 028970d4 5b6c5cd8 yes
- 322 028970e8 5b6c5cd8 yes Duplicate promote/relocs
- ...
+ 0:003> !HistRoot 01e411b8
+ GCCount Value MT Promoted? Notes
+ ---------------------------------------------------------
+ 2296 028970d4 5b6c5cd8 yes
+ 2295 028970d4 5b6c5cd8 yes
+ 2294 028970d4 5b6c5cd8 yes
+ 2293 028970d4 5b6c5cd8 yes
+ 2292 028970d4 5b6c5cd8 yes
+ 2291 028970d4 5b6c5cd8 yes
+ 2290 028970d4 5b6c5cd8 yes
+ 2289 028970d4 5b6c5cd8 yes
+ 2288 028970d4 5b6c5cd8 yes
+ 2287 028970d4 5b6c5cd8 yes
+ 2286 028970d4 5b6c5cd8 yes
+ 2285 028970d4 5b6c5cd8 yes
+ 322 028970e8 5b6c5cd8 yes Duplicate promote/relocs
+ ...
\\
of GC relocations that may have led to the address passed in as an argument.
Conceptually the output is:
- GenN obj_address root1, root2, root3,
- GenN-1 prev_obj_addr root1, root2,
- GenN-2 prev_prev_oa root1, root4,
- ...
+ GenN obj_address root1, root2, root3,
+ GenN-1 prev_obj_addr root1, root2,
+ GenN-2 prev_prev_oa root1, root4,
+ ...
Sample output:
- 0:003> !HistObj 028970d4
- GCCount Object Roots
- ---------------------------------------------------------
- 2296 028970d4 00223fc4, 01e411b8,
- 2295 028970d4 00223fc4, 01e411b8,
- 2294 028970d4 00223fc4, 01e411b8,
- 2293 028970d4 00223fc4, 01e411b8,
- 2292 028970d4 00223fc4, 01e411b8,
- 2291 028970d4 00223fc4, 01e411b8,
- 2290 028970d4 00223fc4, 01e411b8,
- 2289 028970d4 00223fc4, 01e411b8,
- 2288 028970d4 00223fc4, 01e411b8,
- 2287 028970d4 00223fc4, 01e411b8,
- 2286 028970d4 00223fc4, 01e411b8,
- 2285 028970d4 00223fc4, 01e411b8,
- 322 028970d4 01e411b8,
- 0 028970d4
+ 0:003> !HistObj 028970d4
+ GCCount Object Roots
+ ---------------------------------------------------------
+ 2296 028970d4 00223fc4, 01e411b8,
+ 2295 028970d4 00223fc4, 01e411b8,
+ 2294 028970d4 00223fc4, 01e411b8,
+ 2293 028970d4 00223fc4, 01e411b8,
+ 2292 028970d4 00223fc4, 01e411b8,
+ 2291 028970d4 00223fc4, 01e411b8,
+ 2290 028970d4 00223fc4, 01e411b8,
+ 2289 028970d4 00223fc4, 01e411b8,
+ 2288 028970d4 00223fc4, 01e411b8,
+ 2287 028970d4 00223fc4, 01e411b8,
+ 2286 028970d4 00223fc4, 01e411b8,
+ 2285 028970d4 00223fc4, 01e411b8,
+ 322 028970d4 01e411b8,
+ 0 028970d4
\\
Generally there's no need to call this explicitly, as each HistInit will first
cleanup the previous resources.
- 0:003> !HistClear
- Completed successfully.
+ 0:003> !HistClear
+ Completed successfully.
\\
-desktop - switch to the desktop runtime if loaded.
-netcore - switch to the .NET Core runtime if loaded.
--reset - reset all the cached internal SOS state.
+-reset - reset all the cached internal SOS state.
Display internal SOS status, reset the internal cached state, or change between desktop or
netcore runtimes when both are loaded in the process or dump.
DumpDomain (dumpdomain) VerifyHeap
EEHeap (eeheap) FindAppDomain
Name2EE (name2ee) DumpLog (dumplog)
-SyncBlk (syncblk)
+SyncBlk (syncblk) SuppressJitOptimization
DumpMT (dumpmt)
DumpClass (dumpclass)
DumpMD (dumpmd)
(lldb) bpmd Foo.dll Program.Main
>> I got the following error message. Now what?
-
- (lldb) sos DumpStackObjects
- The coreclr module is not loaded yet in the target process
- (lldb)
+
+ (lldb) sos DumpStackObjects
+ The coreclr module is not loaded yet in the target process
+ (lldb)
This means that the clr is not loaded yet, or has been unloaded. You need to
wait until your managed program is running in order to use these commands. If
You might find an object pointer by running DumpStackObjects and choosing
from the resultant list. Here is a simple object:
- (lldb) dumpobj a79d40
- Name: Customer
- MethodTable: 009038ec
- EEClass: 03ee1b84
- Size: 20(0x14) bytes
- (/home/user/pub/unittest)
- Fields:
- MT Field Offset Type VT Attr Value Name
- 009038ec 4000008 4 Customer 0 instance 00a79ce4 name
- 009038ec 4000009 8 Bank 0 instance 00a79d2c bank
+ (lldb) dumpobj a79d40
+ Name: Customer
+ MethodTable: 009038ec
+ EEClass: 03ee1b84
+ Size: 20(0x14) bytes
+ (/home/user/pub/unittest)
+ Fields:
+ MT Field Offset Type VT Attr Value Name
+ 009038ec 4000008 4 Customer 0 instance 00a79ce4 name
+ 009038ec 4000009 8 Bank 0 instance 00a79d2c bank
Note that fields of type Customer and Bank are themselves objects, and you can
run DumpObj on them too. You could look at the field directly in memory using
COMMAND: dumparray.
DumpArray
- [-start <startIndex>]
- [-length <length>]
- [-details]
- [-nofields]
- <array object address>
+ [-start <startIndex>]
+ [-length <length>]
+ [-details]
+ [-nofields]
+ <array object address>
This command allows you to examine elements of an array object.
The arguments in detail:
Example output:
- (lldb) sos DumpArray -start 2 -length 3 -details 00ad28d0
- Name: Value[]
- MethodTable: 03e41044
- EEClass: 03e40fc0
- Size: 132(0x84) bytes
- Array: Rank 1, Number of elements 10, Type VALUETYPE
- Element Type: Value
- [2] 00ad28f0
- Name: Value
- MethodTable 03e40f4c
- EEClass: 03ef1698
- Size: 20(0x14) bytes
- (/home/user/bugs/225271/arraytest)
- Fields:
- MT Field Offset Type Attr Value Name
- 5b9a628c 4000001 0 System.Int32 instance 2 x
- 5b9a628c 4000002 4 System.Int32 instance 4 y
- 5b9a628c 4000003 8 System.Int32 instance 6 z
- [3] 00ad28fc
- Name: Value
- MethodTable 03e40f4c
- EEClass: 03ef1698
- Size: 20(0x14) bytes
- (/home/user/bugs/225271/arraytest)
- Fields:
- MT Field Offset Type Attr Value Name
- 5b9a628c 4000001 0 System.Int32 instance 3 x
- 5b9a628c 4000002 4 System.Int32 instance 6 y
- 5b9a628c 4000003 8 System.Int32 instance 9 z
- [4] 00ad2908
- Name: Value
- MethodTable 03e40f4c
- EEClass: 03ef1698
- Size: 20(0x14) bytes
- (/home/user/bugs/225271/arraytest.exe)
- Fields:
- MT Field Offset Type Attr Value Name
- 5b9a628c 4000001 0 System.Int32 instance 4 x
- 5b9a628c 4000002 4 System.Int32 instance 8 y
- 5b9a628c 4000003 8 System.Int32 instance 12 z
+ (lldb) sos DumpArray -start 2 -length 3 -details 00ad28d0
+ Name: Value[]
+ MethodTable: 03e41044
+ EEClass: 03e40fc0
+ Size: 132(0x84) bytes
+ Array: Rank 1, Number of elements 10, Type VALUETYPE
+ Element Type: Value
+ [2] 00ad28f0
+ Name: Value
+ MethodTable 03e40f4c
+ EEClass: 03ef1698
+ Size: 20(0x14) bytes
+ (/home/user/bugs/225271/arraytest)
+ Fields:
+ MT Field Offset Type Attr Value Name
+ 5b9a628c 4000001 0 System.Int32 instance 2 x
+ 5b9a628c 4000002 4 System.Int32 instance 4 y
+ 5b9a628c 4000003 8 System.Int32 instance 6 z
+ [3] 00ad28fc
+ Name: Value
+ MethodTable 03e40f4c
+ EEClass: 03ef1698
+ Size: 20(0x14) bytes
+ (/home/user/bugs/225271/arraytest)
+ Fields:
+ MT Field Offset Type Attr Value Name
+ 5b9a628c 4000001 0 System.Int32 instance 3 x
+ 5b9a628c 4000002 4 System.Int32 instance 6 y
+ 5b9a628c 4000003 8 System.Int32 instance 9 z
+ [4] 00ad2908
+ Name: Value
+ MethodTable 03e40f4c
+ EEClass: 03ef1698
+ Size: 20(0x14) bytes
+ (/home/user/bugs/225271/arraytest.exe)
+ Fields:
+ MT Field Offset Type Attr Value Name
+ 5b9a628c 4000001 0 System.Int32 instance 4 x
+ 5b9a628c 4000002 4 System.Int32 instance 8 y
+ 5b9a628c 4000003 8 System.Int32 instance 12 z
\\
COMMAND: dumpasync.
When called without options, the output is first a list of objects in the heap,
followed by a report listing all the types found, their size and number:
- (lldb) dumpheap
- Address MT Size
- 00a71000 0015cde8 12 Free
- 00a7100c 0015cde8 12 Free
- 00a71018 0015cde8 12 Free
- 00a71024 5ba58328 68
- 00a71068 5ba58380 68
- 00a710ac 5ba58430 68
- 00a710f0 5ba5dba4 68
- ...
- total 619 objects
- Statistics:
- MT Count TotalSize Class Name
- 5ba7607c 1 12 System.Security.Permissions.HostProtectionResource
- 5ba75d54 1 12 System.Security.Permissions.SecurityPermissionFlag
- 5ba61f18 1 12 System.Collections.CaseInsensitiveComparer
- ...
- 0015cde8 6 10260 Free
- 5ba57bf8 318 18136 System.String
- ...
+ (lldb) dumpheap
+ Address MT Size
+ 00a71000 0015cde8 12 Free
+ 00a7100c 0015cde8 12 Free
+ 00a71018 0015cde8 12 Free
+ 00a71024 5ba58328 68
+ 00a71068 5ba58380 68
+ 00a710ac 5ba58430 68
+ 00a710f0 5ba5dba4 68
+ ...
+ total 619 objects
+ Statistics:
+ MT Count TotalSize Class Name
+ 5ba7607c 1 12 System.Security.Permissions.HostProtectionResource
+ 5ba75d54 1 12 System.Security.Permissions.SecurityPermissionFlag
+ 5ba61f18 1 12 System.Collections.CaseInsensitiveComparer
+ ...
+ 0015cde8 6 10260 Free
+ 5ba57bf8 318 18136 System.String
+ ...
"Free" objects are simply regions of space the garbage collector can use later.
If 30% or more of the heap contains "Free" objects, the process may suffer from
combined with a high rate of allocation. Here is example output where DumpHeap
provides a warning about fragmentation:
- <After the Statistics section>
- Fragmented blocks larger than 1MB:
- Addr Size Followed by
- 00a780c0 1.5MB 00bec800 System.Byte[]
- 00da4e38 1.2MB 00ed2c00 System.Byte[]
- 00f16df0 1.2MB 01044338 System.Byte[]
+ <After the Statistics section>
+ Fragmented blocks larger than 1MB:
+ Addr Size Followed by
+ 00a780c0 1.5MB 00bec800 System.Byte[]
+ 00da4e38 1.2MB 00ed2c00 System.Byte[]
+ 00f16df0 1.2MB 01044338 System.Byte[]
The arguments in detail:
The start/end parameters can be obtained from the output of eeheap -gc. For
example, if you only want to list objects in the large heap segment:
- (lldb) eeheap -gc
- Number of GC Heaps: 1
- generation 0 starts at 0x00c32754
- generation 1 starts at 0x00c32748
- generation 2 starts at 0x00a71000
- segment begin allocated size
- 00a70000 00a71000 010443a8 005d33a8(6108072)
- Large object heap starts at 0x01a71000
- segment begin allocated size
- 01a70000 01a71000 01a75000 0x00004000(16384)
- Total Size 0x5d73a8(6124456)
- ------------------------------
- GC Heap Size 0x5d73a8(6124456)
-
- (lldb) dumpheap 1a71000 1a75000
- Address MT Size
- 01a71000 5ba88bd8 2064
- 01a71810 0019fe48 2032 Free
- 01a72000 5ba88bd8 4096
- 01a73000 0019fe48 4096 Free
- 01a74000 5ba88bd8 4096
- total 5 objects
- Statistics:
- MT Count TotalSize Class Name
- 0019fe48 2 6128 Free
- 5ba88bd8 3 10256 System.Object[]
- Total 5 objects
+ (lldb) eeheap -gc
+ Number of GC Heaps: 1
+ generation 0 starts at 0x00c32754
+ generation 1 starts at 0x00c32748
+ generation 2 starts at 0x00a71000
+ segment begin allocated size
+ 00a70000 00a71000 010443a8 005d33a8(6108072)
+ Large object heap starts at 0x01a71000
+ segment begin allocated size
+ 01a70000 01a71000 01a75000 0x00004000(16384)
+ Total Size 0x5d73a8(6124456)
+ ------------------------------
+ GC Heap Size 0x5d73a8(6124456)
+
+ (lldb) dumpheap 1a71000 1a75000
+ Address MT Size
+ 01a71000 5ba88bd8 2064
+ 01a71810 0019fe48 2032 Free
+ 01a72000 5ba88bd8 4096
+ 01a73000 0019fe48 4096 Free
+ 01a74000 5ba88bd8 4096
+ total 5 objects
+ Statistics:
+ MT Count TotalSize Class Name
+ 0019fe48 2 6128 Free
+ 5ba88bd8 3 10256 System.Object[]
+ Total 5 objects
Finally, if GC heap corruption is present, you may see an error like this:
- (lldb) dumpheap -stat
- object 00a73d24: does not have valid MT
- curr_object : 00a73d24
- Last good object: 00a73d14
- ----------------
+ (lldb) dumpheap -stat
+ object 00a73d24: does not have valid MT
+ curr_object : 00a73d24
+ Last good object: 00a73d14
+ ----------------
That indicates a serious problem. See the help for VerifyHeap for more
information on diagnosing the cause.
a value class is not a first-class object with it's own MethodTable as the
first field. For example:
- (lldb) sos DumpObj a79d98
- Name: Mainy
- MethodTable: 009032d8
- EEClass: 03ee1424
- Size: 28(0x1c) bytes
- (/home/user/pub/unittest)
- Fields:
- MT Field Offset Type Attr Value Name
- 0090320c 4000010 4 VALUETYPE instance 00a79d9c m_valuetype
- 009032d8 400000f 4 CLASS static 00a79d54 m_sExcep
+ (lldb) sos DumpObj a79d98
+ Name: Mainy
+ MethodTable: 009032d8
+ EEClass: 03ee1424
+ Size: 28(0x1c) bytes
+ (/home/user/pub/unittest)
+ Fields:
+ MT Field Offset Type Attr Value Name
+ 0090320c 4000010 4 VALUETYPE instance 00a79d9c m_valuetype
+ 009032d8 400000f 4 CLASS static 00a79d54 m_sExcep
m_valuetype is a value type. The value in the MT column (0090320c) is the
MethodTable for it, and the Value column provides the start address:
- (lldb) sos DumpVC 0090320c 00a79d9c
- Name: Funny
- MethodTable 0090320c
- EEClass: 03ee14b8
- Size: 28(0x1c) bytes
- (/home/user/pub/unittest)
- Fields:
- MT Field Offset Type Attr Value Name
- 0090320c 4000001 0 CLASS instance 00a743d8 signature
- 0090320c 4000002 8 System.Int32 instance 2345 m1
- 0090320c 4000003 10 System.Boolean instance 1 b1
- 0090320c 4000004 c System.Int32 instance 1234 m2
- 0090320c 4000005 4 CLASS instance 00a79d98 backpointer
+ (lldb) sos DumpVC 0090320c 00a79d9c
+ Name: Funny
+ MethodTable 0090320c
+ EEClass: 03ee14b8
+ Size: 28(0x1c) bytes
+ (/home/user/pub/unittest)
+ Fields:
+ MT Field Offset Type Attr Value Name
+ 0090320c 4000001 0 CLASS instance 00a743d8 signature
+ 0090320c 4000002 8 System.Int32 instance 2345 m1
+ 0090320c 4000003 10 System.Boolean instance 1 b1
+ 0090320c 4000004 c System.Int32 instance 1234 m2
+ 0090320c 4000005 4 CLASS instance 00a79d98 backpointer
DumpVC is quite a specialized function. Some managed programs make heavy use
of value classes, while others do not.
Given an address in managed JITTED code, IP2MD attempts to find the MethodDesc
associated with it. For example, this output from K:
- (lldb) bt
+ (lldb) bt
...
frame #9: 0x00007fffffffbf60 0x00007ffff61c6d89 libcoreclr.so`MethodDesc::DoPrestub(this=0x00007ffff041f870, pDispatchingMT=0x0000000000000000) + 3001 at prestub.cpp:1490
frame #10: 0x00007fffffffc140 0x00007ffff61c5f17 libcoreclr.so`::PreStubWorker(pTransitionBlock=0x00007fffffffc9a8, pMD=0x00007ffff041f870) + 1399 at prestub.cpp:1037
frame #23: 0x00007fffffffccb0 0x00007ffff5d6d6dc libcoreclr.so`CallDescrWorkerWithHandler(pCallDescrData=0x00007fffffffce80, fCriticalCall=0) + 476 at callhelpers.cpp:88
frame #24: 0x00007fffffffcd00 0x00007ffff5d6eb38 libcoreclr.so`MethodDescCallSite::CallTargetWorker(this=0x00007fffffffd0c8, pArguments=0x00007fffffffd048) + 2504 at callhelpers.cpp:633
- (lldb) ip2md 0x00007ffff049773c
+ (lldb) ip2md 0x00007ffff049773c
MethodDesc: 00007ffff7f71920
Method Name: Microsoft.Win32.SafeHandles.SafeFileHandle.Open(System.Func`1<Int32>)
Class: 00007ffff0494bf8
debugger "U" function, the entire method from start to finish is printed,
with annotations that convert metadata tokens to names.
- <example output>
- ...
- 03ef015d b901000000 mov ecx,0x1
- 03ef0162 ff156477a25b call dword ptr [mscorlib_dll+0x3c7764 (5ba27764)] (System.Console.InitializeStdOutError(Boolean), mdToken: 06000713)
- 03ef0168 a17c20a701 mov eax,[01a7207c] (Object: SyncTextWriter)
- 03ef016d 89442414 mov [esp+0x14],eax
+ <example output>
+ ...
+ 03ef015d b901000000 mov ecx,0x1
+ 03ef0162 ff156477a25b call dword ptr [mscorlib_dll+0x3c7764 (5ba27764)] (System.Console.InitializeStdOutError(Boolean), mdToken: 06000713)
+ 03ef0168 a17c20a701 mov eax,[01a7207c] (Object: SyncTextWriter)
+ 03ef016d 89442414 mov [esp+0x14],eax
If you pass the -gcinfo flag, you'll get inline display of the GCInfo for
the method. You can also obtain this information with the GCInfo command.
disassembly. The -n (No line numbers) flag can be specified to disable this
behavior.
- <example output>
- ...
- c:\Code\prj.mini\exc.cs @ 38:
- 001b00b0 8b0d3020ab03 mov ecx,dword ptr ds:[3AB2030h] ("Break in debugger. When done type <Enter> to continue: ")
- 001b00b6 e8d5355951 call mscorlib_ni+0x8b3690 (51743690) (System.Console.Write(System.String), mdToken: 0600091b)
- 001b00bb 90 nop
-
- c:\Code\prj.mini\exc.cs @ 39:
- 001b00bc e863cdc651 call mscorlib_ni+0xf8ce24 (51e1ce24) (System.Console.ReadLine(), mdToken: 060008f6)
- >>> 001b00c1 90 nop
- ...
+ <example output>
+ ...
+ c:\Code\prj.mini\exc.cs @ 38:
+ 001b00b0 8b0d3020ab03 mov ecx,dword ptr ds:[3AB2030h] ("Break in debugger. When done type <Enter> to continue: ")
+ 001b00b6 e8d5355951 call mscorlib_ni+0x8b3690 (51743690) (System.Console.Write(System.String), mdToken: 0600091b)
+ 001b00bb 90 nop
+
+ c:\Code\prj.mini\exc.cs @ 39:
+ 001b00bc e863cdc651 call mscorlib_ni+0xf8ce24 (51e1ce24) (System.Console.ReadLine(), mdToken: 060008f6)
+ >>> 001b00c1 90 nop
+ ...
\\
COMMAND: dumpstack.
Sample output:
- (lldb) sos EHInfo 33bbd3a
- MethodDesc: 03310f68
- Method Name: MainClass.Main()
- Class: 03571358
- MethodTable: 0331121c
- mdToken: 0600000b
- Module: 001e2fd8
- IsJitted: yes
- CodeAddr: 033bbca0
+ (lldb) sos EHInfo 33bbd3a
+ MethodDesc: 03310f68
+ Method Name: MainClass.Main()
+ Class: 03571358
+ MethodTable: 0331121c
+ mdToken: 0600000b
+ Module: 001e2fd8
+ IsJitted: yes
+ CodeAddr: 033bbca0
- EHHandler 0: TYPED catch(System.IO.FileNotFoundException)
- Clause: [033bbd2b, 033bbd3c] [8b, 9c]
- Handler: [033bbd3c, 033bbd50] [9c, b0]
+ EHHandler 0: TYPED catch(System.IO.FileNotFoundException)
+ Clause: [033bbd2b, 033bbd3c] [8b, 9c]
+ Handler: [033bbd3c, 033bbd50] [9c, b0]
- EHHandler 1: FINALLY
- Clause: [033bbd83, 033bbda3] [e3, 103]
- Handler: [033bbda3, 033bbdc5] [103, 125]
+ EHHandler 1: FINALLY
+ Clause: [033bbd83, 033bbda3] [e3, 103]
+ Handler: [033bbda3, 033bbdc5] [103, 125]
- EHHandler 2: TYPED catch(System.Exception)
- Clause: [033bbd7a, 033bbdc5] [da, 125]
- Handler: [033bbdc5, 033bbdd6] [125, 136]
+ EHHandler 2: TYPED catch(System.Exception)
+ Clause: [033bbd7a, 033bbdc5] [da, 125]
+ Handler: [033bbdc5, 033bbdd6] [125, 136]
\\
method. For example, the notation "reg EDI becoming live" at offset 0x11 of the
method might correspond to a "mov edi,ecx" statement.
- (lldb) sos GCInfo 5b68dbb8 (5b68dbb8 is the start of a JITTED method)
- entry point 5b68dbb8
- preJIT generated code
- GC info 5b9f2f09
- Method info block:
- method size = 0036
- prolog size = 19
- epilog size = 8
- epilog count = 1
- epilog end = yes
- saved reg. mask = 000B
- ebp frame = yes
- fully interruptible=yes
- double align = no
- security check = no
- exception handlers = no
- local alloc = no
- edit & continue = no
- varargs = no
- argument count = 4
- stack frame size = 1
- untracked count = 5
- var ptr tab count = 0
- epilog at 002E
- 36 D4 8C C7 AA |
- 93 F3 40 05 |
-
- Pointer table:
- 14 | [EBP+14H] an untracked local
- 10 | [EBP+10H] an untracked local
- 0C | [EBP+0CH] an untracked local
- 08 | [EBP+08H] an untracked local
- 44 | [EBP-04H] an untracked local
- F1 79 | 0011 reg EDI becoming live
- 72 | 0013 reg ESI becoming live
- 83 | 0016 push ptr 0
- 8B | 0019 push ptr 1
- 93 | 001C push ptr 2
- 9B | 001F push ptr 3
- 56 | 0025 reg EDX becoming live
- 4A | 0027 reg ECX becoming live
- 0E | 002D reg ECX becoming dead
- 10 | 002D reg EDX becoming dead
- E0 | 002D pop 4 ptrs
- F0 31 | 0036 reg ESI becoming dead
- 38 | 0036 reg EDI becoming dead
- FF |
+ (lldb) sos GCInfo 5b68dbb8 (5b68dbb8 is the start of a JITTED method)
+ entry point 5b68dbb8
+ preJIT generated code
+ GC info 5b9f2f09
+ Method info block:
+ method size = 0036
+ prolog size = 19
+ epilog size = 8
+ epilog count = 1
+ epilog end = yes
+ saved reg. mask = 000B
+ ebp frame = yes
+ fully interruptible=yes
+ double align = no
+ security check = no
+ exception handlers = no
+ local alloc = no
+ edit & continue = no
+ varargs = no
+ argument count = 4
+ stack frame size = 1
+ untracked count = 5
+ var ptr tab count = 0
+ epilog at 002E
+ 36 D4 8C C7 AA |
+ 93 F3 40 05 |
+
+ Pointer table:
+ 14 | [EBP+14H] an untracked local
+ 10 | [EBP+10H] an untracked local
+ 0C | [EBP+0CH] an untracked local
+ 08 | [EBP+08H] an untracked local
+ 44 | [EBP-04H] an untracked local
+ F1 79 | 0011 reg EDI becoming live
+ 72 | 0013 reg ESI becoming live
+ 83 | 0016 push ptr 0
+ 8B | 0019 push ptr 1
+ 93 | 001C push ptr 2
+ 9B | 001F push ptr 3
+ 56 | 0025 reg EDX becoming live
+ 4A | 0027 reg ECX becoming live
+ 0E | 002D reg ECX becoming dead
+ 10 | 002D reg EDX becoming dead
+ E0 | 002D pop 4 ptrs
+ F0 31 | 0036 reg ESI becoming dead
+ 38 | 0036 reg EDI becoming dead
+ FF |
This function is important for CLR Devs, but very difficult for anyone else to
make sense of it. You would usually come to use it if you suspect a gc heap
method name from the metadata, or from the output of the "dumpmt -md" command.
For example:
- public interface I1
- {
- void M1();
- }
- public class ExplicitItfImpl : I1
- {
- ...
- void I1.M1() // this method's name is 'I1.M1'
- { ... }
- }
+ public interface I1
+ {
+ void M1();
+ }
+ public class ExplicitItfImpl : I1
+ {
+ ...
+ void I1.M1() // this method's name is 'I1.M1'
+ { ... }
+ }
- bpmd myapp.dll ExplicitItfImpl.I1.M1
+ bpmd myapp.dll ExplicitItfImpl.I1.M1
bpmd works equally well with generic types. Adding a breakpoint on a generic
breakpoint for any instantiation that will be JIT-ted in the future.
Example for generics:
- Given the following two classes:
+ Given the following two classes:
- class G3<T1, T2, T3>
- {
- ...
- public void F(T1 p1, T2 p2, T3 p3)
- { ... }
- }
+ class G3<T1, T2, T3>
+ {
+ ...
+ public void F(T1 p1, T2 p2, T3 p3)
+ { ... }
+ }
- public class G1<T> {
- // static method
- static public void G<W>(W w)
- { ... }
- }
+ public class G1<T> {
+ // static method
+ static public void G<W>(W w)
+ { ... }
+ }
- One would issue the following commands to set breakpoints on G3.F() and
- G1.G():
+ One would issue the following commands to set breakpoints on G3.F() and
+ G1.G():
- bpmd myapp.dll G3`3.F
- bpmd myapp.dll G1`1.G
+ bpmd myapp.dll G3`3.F
+ bpmd myapp.dll G1`1.G
And for explicitly implemented methods on generic interfaces:
- public interface IT1<T>
- {
- void M1(T t);
- }
+ public interface IT1<T>
+ {
+ void M1(T t);
+ }
- public class ExplicitItfImpl<U> : IT1<U>
- {
- ...
- void IT1<U>.M1(U u) // this method's name is 'IT1<U>.M1'
- { ... }
- }
+ public class ExplicitItfImpl<U> : IT1<U>
+ {
+ ...
+ void IT1<U>.M1(U u) // this method's name is 'IT1<U>.M1'
+ { ... }
+ }
- bpmd bpmd.dll ExplicitItfImpl`1.IT1<U>.M1
+ bpmd bpmd.dll ExplicitItfImpl`1.IT1<U>.M1
Additional examples:
- If IT1 and ExplicitItfImpl are types declared inside another class,
- Outer, the bpmd command would become:
+ If IT1 and ExplicitItfImpl are types declared inside another class,
+ Outer, the bpmd command would become:
- bpmd bpmd.exe Outer+ExplicitItfImpl`1.Outer.IT1<U>.M1
+ bpmd bpmd.exe Outer+ExplicitItfImpl`1.Outer.IT1<U>.M1
- (note that the fully qualified type name for ExplicitItfImpl became
- Outer+ExplicitItfImpl, using the '+' separator, while the method name
- is Outer.IT1<U>.M1, using a '.' as the separator)
+ (note that the fully qualified type name for ExplicitItfImpl became
+ Outer+ExplicitItfImpl, using the '+' separator, while the method name
+ is Outer.IT1<U>.M1, using a '.' as the separator)
- Furthermore, if the Outer class resides in a namespace, NS, the bpmd
- command to use becomes:
+ Furthermore, if the Outer class resides in a namespace, NS, the bpmd
+ command to use becomes:
- bpmd bpmd.dll NS.Outer+ExplicitItfImpl`1.NS.Outer.IT1<U>.M1
+ bpmd bpmd.dll NS.Outer+ExplicitItfImpl`1.NS.Outer.IT1<U>.M1
bpmd does not accept offsets nor parameters in the method name. You can add
an IL offset as an optional parameter separate from the name. If there are overloaded
Here is output for a simple program:
- (lldb) eeheap -gc
- Number of GC Heaps: 1
- generation 0 starts at 0x00a71018
- generation 1 starts at 0x00a7100c
- generation 2 starts at 0x00a71000
- segment begin allocated size
- 00a70000 00a71000 00a7e01c 0000d01c(53276)
- Large object heap starts at 0x01a71000
- segment begin allocated size
- 01a70000 01a71000 01a76000 0x00005000(20480)
- Total Size 0x1201c(73756)
- ------------------------------
- GC Heap Size 0x1201c(73756)
+ (lldb) eeheap -gc
+ Number of GC Heaps: 1
+ generation 0 starts at 0x00a71018
+ generation 1 starts at 0x00a7100c
+ generation 2 starts at 0x00a71000
+ segment begin allocated size
+ 00a70000 00a71000 00a7e01c 0000d01c(53276)
+ Large object heap starts at 0x01a71000
+ segment begin allocated size
+ 01a70000 01a71000 01a76000 0x00005000(20480)
+ Total Size 0x1201c(73756)
+ ------------------------------
+ GC Heap Size 0x1201c(73756)
So the total size of the GC Heap is only 72K. On a large web server, with
multiple processors, you can expect to see a GC Heap of 400MB or more. The
also lists heaps associated with the JIT compiler, and heaps associated with
Modules. For example:
- (lldb) eeheap -loader
- Loader Heap:
- --------------------------------------
- System Domain: 5e0662a0
- LowFrequencyHeap:008f0000(00002000:00001000) Size: 0x00001000 bytes.
- HighFrequencyHeap:008f2000(00008000:00001000) Size: 0x00001000 bytes.
- StubHeap:008fa000(00002000:00001000) Size: 0x00001000 bytes.
- Total size: 0x3000(12288)bytes
- --------------------------------------
- Shared Domain: 5e066970
- LowFrequencyHeap:00920000(00002000:00001000) 03e30000(00010000:00003000) Size: 0x00004000 bytes.
- Wasted: 0x00001000 bytes.
- HighFrequencyHeap:00922000(00008000:00001000) Size: 0x00001000 bytes.
- StubHeap:0092a000(00002000:00001000) Size: 0x00001000 bytes.
- Total size: 0x6000(24576)bytes
- --------------------------------------
- Domain 1: 14f000
- LowFrequencyHeap:00900000(00002000:00001000) 03ee0000(00010000:00003000) Size: 0x00004000 bytes.
- Wasted: 0x00001000 bytes.
- HighFrequencyHeap:00902000(00008000:00003000) Size: 0x00003000 bytes.
- StubHeap:0090a000(00002000:00001000) Size: 0x00001000 bytes.
- Total size: 0x8000(32768)bytes
- --------------------------------------
- Jit code heap:
- Normal JIT:03ef0000(00010000:00002000) Size: 0x00002000 bytes.
- Total size: 0x2000(8192)bytes
- --------------------------------------
- Module Thunk heaps:
- Module 5ba22410: Size: 0x00000000 bytes.
- Module 001c1320: Size: 0x00000000 bytes.
- Module 001c03f0: Size: 0x00000000 bytes.
- Module 001caa38: Size: 0x00000000 bytes.
- Total size: 0x0(0)bytes
- --------------------------------------
- Module Lookup Table heaps:
- Module 5ba22410:Size: 0x00000000 bytes.
- Module 001c1320:Size: 0x00000000 bytes.
- Module 001c03f0:Size: 0x00000000 bytes.
- Module 001caa38:03ec0000(00010000:00002000) Size: 0x00002000 bytes.
- Total size: 0x2000(8192)bytes
- --------------------------------------
- Total LoaderHeap size: 0x15000(86016)bytes
- =======================================
+ (lldb) eeheap -loader
+ Loader Heap:
+ --------------------------------------
+ System Domain: 5e0662a0
+ LowFrequencyHeap:008f0000(00002000:00001000) Size: 0x00001000 bytes.
+ HighFrequencyHeap:008f2000(00008000:00001000) Size: 0x00001000 bytes.
+ StubHeap:008fa000(00002000:00001000) Size: 0x00001000 bytes.
+ Total size: 0x3000(12288)bytes
+ --------------------------------------
+ Shared Domain: 5e066970
+ LowFrequencyHeap:00920000(00002000:00001000) 03e30000(00010000:00003000) Size: 0x00004000 bytes.
+ Wasted: 0x00001000 bytes.
+ HighFrequencyHeap:00922000(00008000:00001000) Size: 0x00001000 bytes.
+ StubHeap:0092a000(00002000:00001000) Size: 0x00001000 bytes.
+ Total size: 0x6000(24576)bytes
+ --------------------------------------
+ Domain 1: 14f000
+ LowFrequencyHeap:00900000(00002000:00001000) 03ee0000(00010000:00003000) Size: 0x00004000 bytes.
+ Wasted: 0x00001000 bytes.
+ HighFrequencyHeap:00902000(00008000:00003000) Size: 0x00003000 bytes.
+ StubHeap:0090a000(00002000:00001000) Size: 0x00001000 bytes.
+ Total size: 0x8000(32768)bytes
+ --------------------------------------
+ Jit code heap:
+ Normal JIT:03ef0000(00010000:00002000) Size: 0x00002000 bytes.
+ Total size: 0x2000(8192)bytes
+ --------------------------------------
+ Module Thunk heaps:
+ Module 5ba22410: Size: 0x00000000 bytes.
+ Module 001c1320: Size: 0x00000000 bytes.
+ Module 001c03f0: Size: 0x00000000 bytes.
+ Module 001caa38: Size: 0x00000000 bytes.
+ Total size: 0x0(0)bytes
+ --------------------------------------
+ Module Lookup Table heaps:
+ Module 5ba22410:Size: 0x00000000 bytes.
+ Module 001c1320:Size: 0x00000000 bytes.
+ Module 001c03f0:Size: 0x00000000 bytes.
+ Module 001caa38:03ec0000(00010000:00002000) Size: 0x00002000 bytes.
+ Total size: 0x2000(8192)bytes
+ --------------------------------------
+ Total LoaderHeap size: 0x15000(86016)bytes
+ =======================================
By using eeheap to keep track of the growth of these private heaps, we are
able to rule out or include them as a source of a memory leak.
This function allows you to turn a class name into a MethodTable and EEClass.
It turns a method name into a MethodDesc. Here is an example for a method:
- (lldb) name2ee unittest.exe MainClass.Main
- Module: 001caa38
- Token: 0x0600000d
- MethodDesc: 00902f40
- Name: MainClass.Main()
- JITTED Code Address: 03ef00b8
+ (lldb) name2ee unittest.exe MainClass.Main
+ Module: 001caa38
+ Token: 0x0600000d
+ MethodDesc: 00902f40
+ Name: MainClass.Main()
+ JITTED Code Address: 03ef00b8
and for a class:
- (lldb) name2ee unittest!MainClass
- Module: 001caa38
- Token: 0x02000005
- MethodTable: 009032d8
- EEClass: 03ee1424
- Name: MainClass
+ (lldb) name2ee unittest!MainClass
+ Module: 001caa38
+ Token: 0x02000005
+ MethodTable: 009032d8
+ EEClass: 03ee1424
+ Name: MainClass
The module you are "browsing" with Name2EE needs to be loaded in the process.
To get a type name exactly right, first browse the module with ILDASM. You
For this kind of module, simply use price as the module name:
- 0:044> name2ee price Price
- Module: 10f028b0 (price, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)
- Token: 0x02000002
- MethodTable: 11a47ae0
- EEClass: 11a538c8
- Name: Price
+ 0:044> name2ee price Price
+ Module: 10f028b0 (price, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)
+ Token: 0x02000002
+ MethodTable: 11a47ae0
+ EEClass: 11a538c8
+ Name: Price
Where are we getting these module names from? Run DumpDomain to see a list of
all loaded modules in all domains. And remember that you can browse all the
This command lists information about a MethodDesc. You can use ip2md to turn
a code address in a managed function into a MethodDesc:
- (lldb) dumpmd 902f40
- Method Name: Mainy.Main()
- Class: 03ee1424
- MethodTable: 009032d8
- mdToken: 0600000d
- Module: 001caa78
- IsJitted: yes
- CodeAddr: 03ef00b8
+ (lldb) dumpmd 902f40
+ Method Name: Mainy.Main()
+ Class: 03ee1424
+ MethodTable: 009032d8
+ mdToken: 0600000d
+ Module: 001caa78
+ IsJitted: yes
+ CodeAddr: 03ef00b8
If IsJitted is "yes," you can run U on the CodeAddr pointer to see a
disassembly of the JITTED code. You can call also DumpClass, DumpMT,
This function allows you to turn a metadata token into a MethodTable or
MethodDesc. Here is an example showing class tokens being resolved:
- (lldb) sos Token2EE unittest.exe 02000003
- Module: 001caa38
- Token: 0x02000003
- MethodTable: 0090375c
- EEClass: 03ee1ae0
- Name: Bank
- (lldb) sos Token2EE image00400000 02000004
- Module: 001caa38
- Token: 0x02000004
- MethodTable: 009038ec
- EEClass: 03ee1b84
- Name: Customer
+ (lldb) sos Token2EE unittest.exe 02000003
+ Module: 001caa38
+ Token: 0x02000003
+ MethodTable: 0090375c
+ EEClass: 03ee1ae0
+ Name: Bank
+ (lldb) sos Token2EE image00400000 02000004
+ Module: 001caa38
+ Token: 0x02000004
+ MethodTable: 009038ec
+ EEClass: 03ee1b84
+ Name: Customer
The module you are "browsing" with Token2EE needs to be loaded in the process.
This function doesn't see much use, especially since a tool like ILDASM can
You can get a Module address from DumpDomain, DumpAssembly and other
functions. Here is sample output:
- (lldb) sos DumpModule 1caa50
- Name: /home/user/pub/unittest
- Attributes: PEFile
- Assembly: 001ca248
- LoaderHeap: 001cab3c
- TypeDefToMethodTableMap: 03ec0010
- TypeRefToMethodTableMap: 03ec0024
- MethodDefToDescMap: 03ec0064
- FieldDefToDescMap: 03ec00a4
- MemberRefToDescMap: 03ec00e8
- FileReferencesMap: 03ec0128
- AssemblyReferencesMap: 03ec012c
- MetaData start address: 00402230 (1888 bytes)
+ (lldb) sos DumpModule 1caa50
+ Name: /home/user/pub/unittest
+ Attributes: PEFile
+ Assembly: 001ca248
+ LoaderHeap: 001cab3c
+ TypeDefToMethodTableMap: 03ec0010
+ TypeRefToMethodTableMap: 03ec0024
+ MethodDefToDescMap: 03ec0064
+ FieldDefToDescMap: 03ec00a4
+ MemberRefToDescMap: 03ec00e8
+ FileReferencesMap: 03ec0128
+ AssemblyReferencesMap: 03ec012c
+ MetaData start address: 00402230 (1888 bytes)
The Maps listed map metadata tokens to CLR data structures. Without going into
too much detail, you can examine memory at those addresses to find the
appropriate structures. For example, the TypeDefToMethodTableMap above can be
examined:
- (lldb) dd 3ec0010
- 03ec0010 00000000 00000000 0090320c 0090375c
- 03ec0020 009038ec ...
+ (lldb) dd 3ec0010
+ 03ec0010 00000000 00000000 0090320c 0090375c
+ 03ec0020 009038ec ...
This means TypeDef token 2 maps to a MethodTable with the value 0090320c. You
can run DumpMT to verify that. The MethodDefToDescMap takes a MethodDef token
There is a new option "-mt", which will display the types defined in a module,
and the types referenced by the module. For example:
- (lldb) sos DumpModule -mt 1aa580
- Name: /home/user/pub/unittest
- ...<etc>...
- MetaData start address: 0040220c (1696 bytes)
+ (lldb) sos DumpModule -mt 1aa580
+ Name: /home/user/pub/unittest
+ ...<etc>...
+ MetaData start address: 0040220c (1696 bytes)
- Types defined in this module
+ Types defined in this module
- MT TypeDef Name
- --------------------------------------------------------------------------
- 030d115c 0x02000002 Funny
- 030d1228 0x02000003 Mainy
+ MT TypeDef Name
+ --------------------------------------------------------------------------
+ 030d115c 0x02000002 Funny
+ 030d1228 0x02000003 Mainy
- Types referenced in this module
+ Types referenced in this module
- MT TypeRef Name
- --------------------------------------------------------------------------
- 030b6420 0x01000001 System.ValueType
- 030b5cb0 0x01000002 System.Object
- 030fceb4 0x01000003 System.Exception
- 0334e374 0x0100000c System.Console
- 03167a50 0x0100000e System.Runtime.InteropServices.GCHandle
- 0336a048 0x0100000f System.GC
+ MT TypeRef Name
+ --------------------------------------------------------------------------
+ 030b6420 0x01000001 System.ValueType
+ 030b5cb0 0x01000002 System.Object
+ 030fceb4 0x01000003 System.Exception
+ 0334e374 0x0100000c System.Console
+ 03167a50 0x0100000e System.Runtime.InteropServices.GCHandle
+ 0336a048 0x0100000f System.GC
\\
Example output:
- (lldb) sos DumpAssembly 1ca248
- Parent Domain: 0014f000
- Name: /home/user/pub/unittest
- ClassLoader: 001ca060
- Module Name
- 001caa50 /home/user/pub/unittest
+ (lldb) sos DumpAssembly 1ca248
+ Parent Domain: 0014f000
+ Name: /home/user/pub/unittest
+ ClassLoader: 001ca060
+ Module Name
+ 001caa50 /home/user/pub/unittest
An assembly can consist of multiple modules, and those will be listed. You can
get an Assembly address from the output of DumpDomain.
DumpRuntimeTypes finds all System.RuntimeType objects in the gc heap and
prints the type name and MethodTable they refer too. Sample output:
- Address Domain MT Type Name
- ------------------------------------------------------------------------------
- a515f4 14a740 5baf8d28 System.TypedReference
- a51608 14a740 5bb05764 System.Globalization.BaseInfoTable
- a51958 14a740 5bb05b24 System.Globalization.CultureInfo
- a51a44 14a740 5bb06298 System.Globalization.GlobalizationAssembly
- a51de0 14a740 5bb069c8 System.Globalization.TextInfo
- a56b98 14a740 5bb12d28 System.Security.Permissions.HostProtectionResource
- a56bbc 14a740 5baf7248 System.Int32
- a56bd0 14a740 5baf3fdc System.String
- a56cfc 14a740 5baf36a4 System.ValueType
- ...
+ Address Domain MT Type Name
+ ------------------------------------------------------------------------------
+ a515f4 14a740 5baf8d28 System.TypedReference
+ a51608 14a740 5bb05764 System.Globalization.BaseInfoTable
+ a51958 14a740 5bb05b24 System.Globalization.CultureInfo
+ a51a44 14a740 5bb06298 System.Globalization.GlobalizationAssembly
+ a51de0 14a740 5bb069c8 System.Globalization.TextInfo
+ a56b98 14a740 5bb12d28 System.Security.Permissions.HostProtectionResource
+ a56bbc 14a740 5baf7248 System.Int32
+ a56bd0 14a740 5baf3fdc System.String
+ a56cfc 14a740 5baf36a4 System.ValueType
+ ...
This command will print a "?" in the domain column if the type is loaded into multiple
AppDomains. For example:
If an error is found, VerifyHeap will report it. I'll take a perfectly good
object and corrupt it:
- (lldb) dumpobj a79d40
- Name: Customer
- MethodTable: 009038ec
- EEClass: 03ee1b84
- Size: 20(0x14) bytes
- (/home/user/pub/unittest)
- Fields:
- MT Field Offset Type Attr Value Name
- 009038ec 4000008 4 CLASS instance 00a79ce4 name
- 009038ec 4000009 8 CLASS instance 00a79d2c bank
- 009038ec 400000a c System.Boolean instance 1 valid
-
- (lldb) ed a79d40+4 01 (change the name field to the bogus pointer value 1)
- (lldb) sos VerifyHeap
- object 01ee60dc: bad member 00000003 at 01EE6168
- Last good object: 01EE60C4.
+ (lldb) dumpobj a79d40
+ Name: Customer
+ MethodTable: 009038ec
+ EEClass: 03ee1b84
+ Size: 20(0x14) bytes
+ (/home/user/pub/unittest)
+ Fields:
+ MT Field Offset Type Attr Value Name
+ 009038ec 4000008 4 CLASS instance 00a79ce4 name
+ 009038ec 4000009 8 CLASS instance 00a79d2c bank
+ 009038ec 400000a c System.Boolean instance 1 valid
+
+ (lldb) ed a79d40+4 01 (change the name field to the bogus pointer value 1)
+ (lldb) sos VerifyHeap
+ object 01ee60dc: bad member 00000003 at 01EE6168
+ Last good object: 01EE60C4.
If this gc heap corruption exists, there is a serious bug in your own code or
in the CLR. In user code, an error in constructing PInvoke calls can cause
!GCWhere displays the location in the GC heap of the argument passed in.
- 0:002> !GCWhere 02800038
- Address Gen Heap segment begin allocated size
- 02800038 2 0 02800000 02800038 0282b740 12
+ 0:002> !GCWhere 02800038
+ Address Gen Heap segment begin allocated size
+ 02800038 2 0 02800000 02800038 0282b740 12
When the argument lies in the managed heap, but is not a valid *object* address
the "size" is displayed as 0:
- 0:002> !GCWhere 0280003c
- Address Gen Heap segment begin allocated size
- 0280003c 2 0 02800000 02800038 0282b740 0
+ 0:002> !GCWhere 0280003c
+ Address Gen Heap segment begin allocated size
+ 0280003c 2 0 02800000 02800038 0282b740 0
\\
COMMAND: dumplog.
The optional argument addr allows one to specify a stress log other then the
default one.
- (lldb) dumplog
- Attempting to dump Stress log to file 'StressLog.txt'
- .................
- SUCCESS: Stress log dumped
+ (lldb) dumplog
+ Attempting to dump Stress log to file 'StressLog.txt'
+ .................
+ SUCCESS: Stress log dumped
To turn on the stress log, set the following environment variables before
starting the .NET Core app:
Here is some sample output:
- 3560 9.981137099 : `SYNC` RareEnablePremptiveGC: entering.
- Thread state = a030
+ 3560 9.981137099 : `SYNC` RareEnablePremptiveGC: entering.
+ Thread state = a030
- 3560 9.981135033 : `GC`GCALLOC`GCROOTS` ========== ENDGC 4194 (gen = 2,
- collect_classes = 0) ==========={
+ 3560 9.981135033 : `GC`GCALLOC`GCROOTS` ========== ENDGC 4194 (gen = 2,
+ collect_classes = 0) ==========={
- 3560 9.981125826 : `GC` Segment mem 00C61000 alloc
- = 00D071F0 used 00D09254 committed 00D17000
+ 3560 9.981125826 : `GC` Segment mem 00C61000 alloc
+ = 00D071F0 used 00D09254 committed 00D17000
- 3560 9.981125726 : `GC` Generation 0 [00CED07C, 00000000
- ] cur = 00000000
+ 3560 9.981125726 : `GC` Generation 0 [00CED07C, 00000000
+ ] cur = 00000000
- 3560 9.981125529 : `GC` Generation 1 [00CED070, 00000000
- ] cur = 00000000
+ 3560 9.981125529 : `GC` Generation 1 [00CED070, 00000000
+ ] cur = 00000000
- 3560 9.981125103 : `GC` Generation 2 [00C61000, 00000000
- ] cur = 00000000
+ 3560 9.981125103 : `GC` Generation 2 [00C61000, 00000000
+ ] cur = 00000000
- 3560 9.981124963 : `GC` GC Heap 00000000
+ 3560 9.981124963 : `GC` GC Heap 00000000
- 3560 9.980618994 : `GC`GCROOTS` GcScanHandles (Promotion Phase = 0)
+ 3560 9.980618994 : `GC`GCROOTS` GcScanHandles (Promotion Phase = 0)
The first column is the OS thread ID for the thread appending to the log,
the second column is the timestamp, the third is the facility category for the
FindAppDomain will attempt to resolve the AppDomain of an object. For example,
using an Object Pointer from the output of DumpStackObjects:
- (lldb) sos FindAppDomain 00a79d98
- AppDomain: 0014f000
- Name: unittest.exe
- ID: 1
+ (lldb) sos FindAppDomain 00a79d98
+ AppDomain: 0014f000
+ Name: unittest.exe
+ ID: 1
You can find out more about the AppDomain with the DumpDomain command. Not
every object has enough clues about it's origin to determine the AppDomain.
Sample output:
- (lldb) histinit
- Attempting to read Stress log
- STRESS LOG:
- facilitiesToLog = 0xffffffff
- levelToLog = 6
- MaxLogSizePerThread = 0x10000 (65536)
- MaxTotalLogSize = 0x1000000 (16777216)
- CurrentTotalLogChunk = 9
- ThreadsWithLogs = 3
- Clock frequency = 3.392 GHz
- Start time 15:26:31
- Last message time 15:26:56
- Total elapsed time 25.077 sec
- .....................................
- ---------------------------- 2407 total entries -----------------------------
-
-
- SUCCESS: GCHist structures initialized
+ (lldb) histinit
+ Attempting to read Stress log
+ STRESS LOG:
+ facilitiesToLog = 0xffffffff
+ levelToLog = 6
+ MaxLogSizePerThread = 0x10000 (65536)
+ MaxTotalLogSize = 0x1000000 (16777216)
+ CurrentTotalLogChunk = 9
+ ThreadsWithLogs = 3
+ Clock frequency = 3.392 GHz
+ Start time 15:26:31
+ Last message time 15:26:56
+ Total elapsed time 25.077 sec
+ .....................................
+ ---------------------------- 2407 total entries -----------------------------
+
+
+ SUCCESS: GCHist structures initialized
\\
would use this command. The output of this command contains all entries that
reference the object:
- (lldb) histobjfind 028970d4
- GCCount Object Message
- ---------------------------------------------------------
- 2296 028970d4 Promotion for root 01e411b8 (MT = 5b6c5cd8)
- 2296 028970d4 Relocation NEWVALUE for root 00223fc4
- 2296 028970d4 Relocation NEWVALUE for root 01e411b8
- ...
- 2295 028970d4 Promotion for root 01e411b8 (MT = 5b6c5cd8)
- 2295 028970d4 Relocation NEWVALUE for root 00223fc4
- 2295 028970d4 Relocation NEWVALUE for root 01e411b8
- ...
+ (lldb) histobjfind 028970d4
+ GCCount Object Message
+ ---------------------------------------------------------
+ 2296 028970d4 Promotion for root 01e411b8 (MT = 5b6c5cd8)
+ 2296 028970d4 Relocation NEWVALUE for root 00223fc4
+ 2296 028970d4 Relocation NEWVALUE for root 01e411b8
+ ...
+ 2295 028970d4 Promotion for root 01e411b8 (MT = 5b6c5cd8)
+ 2295 028970d4 Relocation NEWVALUE for root 00223fc4
+ 2295 028970d4 Relocation NEWVALUE for root 01e411b8
+ ...
\\
HistRoot provides information related to both promotions and relocations of the
root specified as the argument.
- (lldb) histroot 01e411b8
- GCCount Value MT Promoted? Notes
- ---------------------------------------------------------
- 2296 028970d4 5b6c5cd8 yes
- 2295 028970d4 5b6c5cd8 yes
- 2294 028970d4 5b6c5cd8 yes
- 2293 028970d4 5b6c5cd8 yes
- 2292 028970d4 5b6c5cd8 yes
- 2291 028970d4 5b6c5cd8 yes
- 2290 028970d4 5b6c5cd8 yes
- 2289 028970d4 5b6c5cd8 yes
- 2288 028970d4 5b6c5cd8 yes
- 2287 028970d4 5b6c5cd8 yes
- 2286 028970d4 5b6c5cd8 yes
- 2285 028970d4 5b6c5cd8 yes
- 322 028970e8 5b6c5cd8 yes Duplicate promote/relocs
- ...
+ (lldb) histroot 01e411b8
+ GCCount Value MT Promoted? Notes
+ ---------------------------------------------------------
+ 2296 028970d4 5b6c5cd8 yes
+ 2295 028970d4 5b6c5cd8 yes
+ 2294 028970d4 5b6c5cd8 yes
+ 2293 028970d4 5b6c5cd8 yes
+ 2292 028970d4 5b6c5cd8 yes
+ 2291 028970d4 5b6c5cd8 yes
+ 2290 028970d4 5b6c5cd8 yes
+ 2289 028970d4 5b6c5cd8 yes
+ 2288 028970d4 5b6c5cd8 yes
+ 2287 028970d4 5b6c5cd8 yes
+ 2286 028970d4 5b6c5cd8 yes
+ 2285 028970d4 5b6c5cd8 yes
+ 322 028970e8 5b6c5cd8 yes Duplicate promote/relocs
+ ...
\\
of GC relocations that may have led to the address passed in as an argument.
Conceptually the output is:
- GenN obj_address root1, root2, root3,
- GenN-1 prev_obj_addr root1, root2,
- GenN-2 prev_prev_oa root1, root4,
- ...
+ GenN obj_address root1, root2, root3,
+ GenN-1 prev_obj_addr root1, root2,
+ GenN-2 prev_prev_oa root1, root4,
+ ...
Sample output:
- (lldb) histobj 028970d4
- GCCount Object Roots
- ---------------------------------------------------------
- 2296 028970d4 00223fc4, 01e411b8,
- 2295 028970d4 00223fc4, 01e411b8,
- 2294 028970d4 00223fc4, 01e411b8,
- 2293 028970d4 00223fc4, 01e411b8,
- 2292 028970d4 00223fc4, 01e411b8,
- 2291 028970d4 00223fc4, 01e411b8,
- 2290 028970d4 00223fc4, 01e411b8,
- 2289 028970d4 00223fc4, 01e411b8,
- 2288 028970d4 00223fc4, 01e411b8,
- 2287 028970d4 00223fc4, 01e411b8,
- 2286 028970d4 00223fc4, 01e411b8,
- 2285 028970d4 00223fc4, 01e411b8,
- 322 028970d4 01e411b8,
- 0 028970d4
+ (lldb) histobj 028970d4
+ GCCount Object Roots
+ ---------------------------------------------------------
+ 2296 028970d4 00223fc4, 01e411b8,
+ 2295 028970d4 00223fc4, 01e411b8,
+ 2294 028970d4 00223fc4, 01e411b8,
+ 2293 028970d4 00223fc4, 01e411b8,
+ 2292 028970d4 00223fc4, 01e411b8,
+ 2291 028970d4 00223fc4, 01e411b8,
+ 2290 028970d4 00223fc4, 01e411b8,
+ 2289 028970d4 00223fc4, 01e411b8,
+ 2288 028970d4 00223fc4, 01e411b8,
+ 2287 028970d4 00223fc4, 01e411b8,
+ 2286 028970d4 00223fc4, 01e411b8,
+ 2285 028970d4 00223fc4, 01e411b8,
+ 322 028970d4 01e411b8,
+ 0 028970d4
\\
Generally there's no need to call this explicitly, as each HistInit will first
cleanup the previous resources.
- (lldb) histclear
- Completed successfully.
+ (lldb) histclear
+ Completed successfully.
\\