New commands in SOS for .NET 4.0 Part 1
My friend and fellow debugger Brian at https://Kodehoved.dk recently wrote a couple of posts on news with sos for .NET framework 4.0 (in Danish)
New SOS Commands in .NET 4
More debugging news in CLR 4
Since Danish, although a beautiful language is probably foreign to most of you I figured I’d write a summary of the new commands in English and add some comments of my own.
Loading sos for .NET 4.0
As in 2.0 you will find sos.dll in the framework directory so you can load it in windbg or cdb using the full path
.load C:\Windows\Microsoft.NET\Framework\v4.0.30128\sos.dll
You can also use the short hand .loadby method but since the name of the core dll has changed in 4.0, you will no longer load it using .loadby sos mscorwks, instead you can now load it using
.loadby sos clr
SOS now takes advantage of windbg’s DML feature making it easier to debug
DML stands for Debugger Markup Language and allows commands to emit hyper links in the command output. For example, in the !threads command output there are DML links for the OSID column, the State column and the Domain column.
Clicking on the first link in the OSID column (below) for example would execute the command ~~[ff4]s which would set the context to that thread. Clicking on a link in the state column would show you the !ThreadState output so you can see exactly what the state 8220 means etc. This is very handy as you don’t have to remember all the various commands.
0:042> !threads
ThreadCount: 25
UnstartedThread: 0
BackgroundThread: 17
PendingThread: 0
DeadThread: 8
Hosted Runtime: no
PreEmptive GC Alloc Lock
ID OSID ThreadOBJ State GC Context Domain Count APT Exception
11 1 ff4 012923d0 8220 Enabled 00000000:00000000 01289450 0 Ukn
18 2 1dbc 0129a3a0 b220 Enabled 00000000:00000000 01289450 0 MTA (Finalizer)
20 4 114c 012b1650 8008220 Enabled 00000000:00000000 01289450 0 MTA (Threadpool Completion Port)
…
In order to turn on DML in your debugger you can run the command .prefer_dml 1 or if you only want to enable it for a specific command you can run !threads /D for example.
DML is used in many places in sos… in !dumpheap –stat you get links for each type that executed !dumpheap –mt <methodtable> so that you can see all the objects of that type, and the !dumpobj output emits links so that you can easily click and look at the member variables in more detail.
New commands
To find a list of all the commands sos has to offer you can run !help in windbg (if sos is the last extension that was loaded) and to get help (including examples) for a specific command you can run !help <command>, for example !help DumpObj.
Understanding why an object is not garbaqe collected (!GCWhere, !FindRoots !HandleCLRN)
Previously we only had the !GCRoot command which was nice for strong references but didn’t work well when your object was not “really” rooted.
Running !GCRoot <object address> will tell us the root chain of any rooted object, in other words, if your object is not being collected because it is linked, directly or indirectly from a thread, a static object, a ref counted object etc. it will give you this link chain so that you can determine which links you need to break in order to make your object collectable.
Sometimes however you may be troubleshooting an issue where your object is not necessarily rooted but it still doesn’t get collected. The answer to why it is not collected is either that the generation your object is in has yet to be collected, or it is rooted by an object in a higher generation, and that it is waiting for this object to be collected.
If you are live debugging your application with Windbg you can now find out why your object is not collected by going through this sequence.
1. Find out which generation your object is in by running !GCWhere
0:030> !GCWhere 057cca48 Address Gen Heap segment begin allocated size 057cca48 2 1 056f0000 056f0038 065c8a04 0x40(64)
!GCWhere tells you what generation your object currently belongs to, as well as some info about the segment in which it is allocated. In this case our object is in Gen 2 on Heap 1.
2. Turn on CLR GC Notifications
Next we run !HandleCLRN to tell the debugger to stop on GC CLR Notifications
3. Enable break on GC
!FindRoots –gen 2 tells the debugger to stop on the next Gen 2 collection, so we issue this command and hit g (for go) to allow the debugger to continue executing
0:030> !FindRoots -gen 2 0:030> g
4. Find the roots for your object
When the garbage collection occurs the following is displayed in windbg and the debugger stops
(21d0.1a74): CLR notification exception - code e0444143 (first chance)
CLR notification: GC - Performing a gen 2 collection. Determined surviving objects...
Now we can run !FindRoots <object address> to determine what is holding on to the object. This might be a root graph similar to what you see with !gcroot if the object is strongly rooted.
It might also be something like:
0:016> !FindRoots 05e54f4c Object 05e54f4c will survive this collection: gen(0x5e54f4c) = 2 > 1 = condemned generation.
… if you do findroots for an object in a higher generation than the one you stopped on… or something like
0:002> !findroots 06808094 older generations::Root: 068012f8(AAA.Test+a)-> 06808094(AAA.Test+b)
… if your object is being held on to by an object in an older generation
There are plenty of other new commands as well but to avoid making this post all too long, I will continue with the other commands in my next post instead.
Until then,
Tess
Comments
Anonymous
March 01, 2010
Great info Tess! Thanks for thinking about translation.Anonymous
January 17, 2011
Hi Tess, I am trying to debug a 64bit w3wp process (Sharepoint 2010) in a 64bit machine . After loading sos through .loadby sos clr, when I try to run any other commans I see the following message !threads The version of SOS does not match the version of CLR you are debugging. Please load the matching version of SOS for the version of CLR you are debugging. CLR Version: 4.0.30319.1 SOS Version: 2.0.50727.4952 Failed to request ThreadStore I have spent the whole day today trying to figure what could be happening but in vain. Any hints would be greatly appreciated!Anonymous
April 11, 2011
Mallika: As you can see by the version numbers, you've inadvertently loaded the .NET 2.0 version of SOS. Try again but use the full path to the .NET 4 - like this: .load c:WindowsMicrosoft.NETFrameworkv4.0.30319SOS.dll that should do itAnonymous
May 11, 2011
Is this an issue or just a distruction: The version of SOS does not match the version of CLR you are debugging. Please load the matching version of SOS for the version of CLR you are debugging. CLR Version: 4.0.30319.1 SOS Version: 4.0.30319.225Anonymous
April 02, 2013
Same issue here :( The version of SOS does not match the version of CLR you are debugging. Please load the matching version of SOS for the version of CLR you are debugging. CLR Version: 4.0.30319.17929 SOS Version: 4.0.30319.296Anonymous
January 07, 2014
Just little late on the response: But you may want to get two things along with memory dump, mscordacwks.dll & sos.dll from the machine where dump was taken. Copy them into a separate folder e.g. c:debugext and use .load to load them. If you still get the error, use .chain command to find how the sos.dll and mscordacwks.dll is loaded, in certain cases, you may end up seeing two sos.dll with different version loaded in debug session, so, just unload the one which is not correct by using .unload command.