In my last blog I talked a bit about how you go about using Visual Studio to look at "Release" code so that you can find out what code is actually generated by a particular high level programming construct. As a quick recap the tricky part of insuring this is to
In upcoming blog entries I am going to talk about how to use this general technique to answer questions like 'how to static, non-virtual, virtual, interface, and delegate calls compare'? Before I start that, there is another very useful technique that I wanted to show you.
The SOS Extension DLL
Microsoft current support two very different debugging tools:
Visual Studio has a lot of built in support for managed (.NET Runtime), code. However the 'windbg' debuggers did not. However there are times (eg in the field), where you might not have a Visual Studio handy and need to fall back on windbg. To make managed debugging possible the .NET Rutime team developed an 'extension' DLL that can be loaded by the 'windbg' debugger. This extension DLL understands how to decode various .NET Runtime data structures and is INDISPENSIBLE for debugging managed code if you are not using Visual Studio. For example see the MSDN article on production debugging for an example of using windbg and SOS to debug a 'memory leak' in a production ASP.NET scenario.
Using the SOS DLL in Visual Studio.
It is not particularly well known that you can also use the .NET Runtime SOS DLL in Visual Studio. This allows you to combine the ease of use of Visual Studio with some of the powerful features of the SOS.DLL. Note that this feature does NOT exist in VS 2003. You need to upgrade to VS 2005 for the following to work.
Debugger Modes
To use the SOS.DLL you need to know a bit more about 'debugging modes' in Visual Studio. Most of the time when you are debugging managed code, you don't care about operating system calls, or other calls out to unmanaged code. By default when a managed application is run under Visual Studio, it runs in 'managed mode' where only managed code is shown. Calls out to the runtime or to unmanaged code simply can't be viewed. This is very annoying for people who want to see all the underlying instructions (like me). You can however tell Visual Studio to debug ONLY unmanaged code, or to debug both. The SOS dll can only be used when Visual Studio is debugging in unmanaged mode or in 'both'.
Unfortunately, the exact mechanism for selecting the debugging mode varies. For C# projects, you select you select the project's properties (right click on the project icon in the 'Solution Explorer' window on the right of the screen), and select the 'Debug' tab. Under it you will find a box labeled 'Enable unmanaged code debugging'. Checking this box puts the debugger in 'both' mode and allows the SOS DLL to be used.
If you attach to an existing process, the 'Attach to Process' dialog has a 'Attach To' box that has a 'Select' button. Clicking on this leads to a dialog where you can select both 'managed' and 'native' code which will also put the debugger into 'both' mode.
Finally you can start the debugger on a exe (eg hello.exe arg1 arg2), using the command below
When Visual Studio is brought up in this way, you can access the debugger properties by right clicking on the exe name in the Solution Explorer window. One of the properties is 'debugger Type' and can be set to 'Mixed' to enable 'both' mode.
Loading SOS
Once you have selected the debugger type, you are ready to load SOS. To do so you need to open the debuggers 'Immediate Window' (Debug->Windows->Immediate). The Immediate window is basically a place where you an type commands and see the results (a non-GUI debugger). To load SOS simply step into your application (F10)
It should reply with a message like
· extension C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll loaded
At this point you can type SOS commands. All such commands begin with a ! mark. The most important of these is the following command
which tells you about the rest of the commands. For example, one of the more interesting commands is the !DumpHeap -stat which shows you a histogram of GC heap (grouped by object type).
More complete details of using this command to find 'leaks' (memory that should be trash, but erroneously it being referenced), is detailed in production debugging article.
One of my favorite commands is the !u command. This command disassembles code, but also annotates it with useful symbolic information like the names of .NET Runtime helper routines. We will see this in action in a later blog.
Recap
I think I have done enough for one blog entry. What we have covered in this entry is