How to display managed objects with certain value in one of the fields in WinDbg using SOS (or SOSEX)?

2.6k views Asked by At

My problem is this:

0:000> !DumpHeap -type Microsoft.Internal.ReadLock -stat
------------------------------
Heap 0
total 0 objects
------------------------------
Heap 1
total 0 objects
------------------------------
Heap 2
total 0 objects
------------------------------
Heap 3
total 0 objects
------------------------------
total 0 objects
Statistics:
              MT    Count    TotalSize Class Name
000007fef3d14088    74247      2375904 Microsoft.Internal.ReadLock
Total 74247 objects

The way I read this output is that I have 74,247 Microsoft.Internal.ReadLock instances on my heap. However, some of them are probably pending collection.

I want to display only those which are not pending collection.

For example, 0000000080f88e90 is the address of one of these objects and it is garbage. I know it, because:

0:000> !mroot 0000000080f88e90
No root paths were found.
0:000> !refs 0000000080f88e90 -target
Objects referencing 0000000080f88e90 (Microsoft.Internal.ReadLock):
NONE
0:000> !do 0000000080f88e90
Name:        Microsoft.Internal.ReadLock
MethodTable: 000007fef3d14088
EEClass:     000007fef3c63410
Size:        32(0x20) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.ComponentModel.Composition\v4.0_4.0.0.0__b77a5c561934e089\System.ComponentModel.Composition.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fef3d13fb0  400001e        8 ...oft.Internal.Lock  0 instance 0000000080001010 _lock
000007fef0a8c7d8  400001f       10         System.Int32  1 instance                1 _isDisposed

As one can see, both sosex.mroot and sosex.refs indicate no one references it, plus dumping its fields reveals that it was disposed through IDisposable, so it makes sense that the object is garbage (I know that being disposed does not imply the object is garbage, but it is in this case).

Now I want to display all those instances which are not garbage. I guess I am to use the .foreach command. Something like this:

.foreach(entry {!dumpheap -type Microsoft.Internal.ReadLock -short}){.if (???) {.printf "%p\n", entry} }

My problem is that I have no idea what goes into the .if condition.

I am able to inspect the _isDisposed field like this:

0:000> dd 0000000080f88e90+10 L1
00000000`80f88ea0  00000001

But .if expects an expression and all I have is a command output. If I knew how to extract information from the command output and arrange it as an expression then I could use it as the .if condition and be good.

So, my question is this - is there a way to get the field value as an expression suitable for .if? Alternatively, is it possible to parse the command output in a way suitable for using the result as the .if condition?

1

There are 1 answers

2
Thomas Weller On BEST ANSWER

I didn't have an example which uses ReadLock objects, but I tried with Strings and this is my result:

.foreach (entry {!dumpheap -short -type Microsoft.Internal.ReadLock}) 
{ 
    .if (poi(${entry}+10) == 1)  
    {
         .printf "%p\n", ${entry}
    }
}

I'm using poi() to get pointer size data from the address. Also note I'm using ${entry} not entry in both, poi() and .printf. You might also like !do ${entry} inside the .if.

In one line for copy/paste:

.foreach (entry {!dumpheap -short -type Microsoft.Internal.ReadLock}) {.if (poi(${entry}+10) == 1) {.printf "%p\n", ${entry}}}