Identifying Specific Reference Type Arrays with SOS

May 1, 2014

no comments

When you’re looking for arrays of a specific type using SOS, you might notice a weird phenomenon. Value type arrays (such as System.Int32[]) will be shown properly regardless of which command you use, but reference type arrays (such as System.String[]) exhibit some weird behavior. Here’s an example:

0:000> !dumpheap -stat
Statistics:
              MT Count TotalSize Class Name
...
00007ffecf435740     2       304 System.Byte[]
00007ffecf4301c8     2       320 System.Threading.ThreadAbortException
00007ffecf4327d8    11       696 System.Int32[]
00007ffecf42da78     3       720 System.Collections.Generic.Dictionary`2+Entry[[System.Type, mscorlib],[System.Security.Policy.EvidenceTypeDescriptor, mscorlib]][]
00007ffecf430f48     4       766 System.Char[]
00007ffecf4345a8     2      1072 System.Globalization.CultureData
00007ffecf431d70    26      1456 System.RuntimeType
00007ffecf42fc48   162      7428 System.String
00007ffecf4302c0    27     36400 System.Object[]

As you can see, System.Byte[], System.Int32[] and System.Char[] are clearly visible and have distinct method table pointers, but reference type arrays are nowhere to be seen. Let’s take a look at all the System.Object[] instances:

0:000> !dumpheap -mt 00007ffecf4302c0       
         Address               MT     Size
00000079d06518e0 00007ffecf4302c0      176     
00000079d06524f0 00007ffecf4302c0      112     
00000079d0652d88 00007ffecf4302c0       32     
00000079d0652dd0 00007ffecf4302c0      112     
00000079d0653d38 00007ffecf4302c0      112     
00000079d0653de8 00007ffecf4302c0       40     
00000079d0653e10 00007ffecf4302c0       64     
00000079d0653e50 00007ffecf4302c0       40     
00000079d0653e98 00007ffecf4302c0      216     
...

It looks like they all have the same method table pointer. And indeed, it would make sense because there’s no reason to duplicate methods on reference type arrays. The JITted code is exactly the same. But when you look at the arrays individually, you can easily identify the specific element type:

0:000> !do 00000079d0652dd0 
Name:        System.String[]
MethodTable: 00007ffecf4302c0
EEClass:     00007ffecee6f5f0
Size:        112(0x70) bytes
Array:       Rank 1, Number of elements 10, Type CLASS
Fields:
None

And there it is — the debugger’s telling us that this is an array of strings. How does it know, considering that the method table pointer is the same? It looks at the third QWORD of the array object, which is the element type method table:

0:000> dq 00000079d0652dd0 L3
00000079`d0652dd0  00007ffe`cf4302c0 00000000`0000000a
00000079`d0652de0  00007ffe`cf42fc48

0:000> !dumpmt 00007ffe`cf42fc48
EEClass:         00007ffecedc1aa8
Module:          00007ffecedc1000
Name:            System.String
...

It’s kind of annoying, but you could conceive a way of checking this automatically. For example, if you’re looking for all the arrays of type System.String[], then — assuming you already know the MT for System.String — you could issue the following loop:

.foreach (arr {!dumpheap -mt 00007ffecf4302c0 -short}) { .if (poi( arr +0n16) == 0x00007ffecf42fc48) { !dumparray arr } }

But there’s in fact an easier alternative. It turns out that !dumpheap can actually determine the array type for us, so the preceding loop can be replaced with a simple:

!dumpheap -type System.String[]

And there we have it, a way to display arrays of a specific reference type using SOS.


I am posting short links and updates on Twitter as well as on this blog. You can follow me: @goldshtn

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>