Look at WinDbg Commands For Advanced .NET Debugging

This article describes the WinDbg commands helpful for analyzing an ASP.NET memory dump. We need to load SOS.dll or psscor2.dll for .NET 2.0 applications or psscor4.dll for .NET 4.0 applications into WinDbg for analyzing managed code. SOS.dll is available in the .NET Framework folder and psscor2.dll can be downloaded from here and psscor4.dll from here. We might need to collect a memory dump of w3wp.exe in scenarios like crash, hang, High CPU or memory, deadlocks of your website using ProcDump or DebugDiag. After collecting the dump, we need to open it in WinDbg by dragging and dropping or "File" -> "Open Crash Dump". We then need to configure it to point to the Microsoft Symbol server by running .symfix followed by .sympath as shown below:
Let's load SOS.dll or psscor2.dll for 2.0 apps or psscor4.dll for 4.0 apps. The psscor extension is a superset of sos.dll and we will load it using the following command:
.load C:\Program Files\DebugDiag\Exts\psscor4.dll (or) .load psscor4 followed by .reload
We can load sos.dll based on the .NET app version using the following command:
.loadby sos clr
We are now ready to analyze the managed code using pscor4.dll. Let's look at commonly used commands.
Command: .help (or) !psscor4.help
Purpose: This command shows all the commands supported by the extension.
Command: !help <command>
Purpose: This command gives information about a specific command like options, purpose, and so on.
Command: !runaway
Purpose: This command lists all threads within the w3p.exe along with the time consumed by it.
Output [Here 28, 26, 27 are thread Ids]:
Command: !threadpool
Purpose: This command shows ThreadPool information CPU usage, as the number of work requests in the queue, timers and completion port threads, and so on.
Command: ~<threadId>s
Purpose: This command switches to a specific thread.
Command: !clrstack
Purpose: This command shows a managed stack trace of a thread.
Command: k (or) kp [shows parameters] (or) kn [shows Frame numbers as well]
Purpose: This command shows managed and unmanaged stack traces of a thread.
Command: !dso (or) !DumpStackObjects
Purpose: This command shows all the objects that are on the thread's stack.
Command: !do <object>
Purpose: This command shows object information like Method Table, EEClass, size, fields, and so on.
Command: !DumpHeap
Purpose: This command shows objects present on the heap.
Command: !DumpHeap -stat
Purpose: This command shows statistics of all objects in the heap; the number of objects of a given type, type name, and so on.
Command: !sam path (or) !SaveAllModules path
Purpose: This command extracts all modules/DLLs from your memory dump to a folder.
There are many more commands available for us, we can explore it using !help <command>. We can use the following procedure as a base for troubleshooting scenarios like a crash, hang, and so on.
Crash Scenario
  1. WinDbg opens the dump pointing to the thread that crashed the process.
  2. Load sos.dll or psscorX.dll and look at the stack trace using !clrstack. This helps us to determine which method threw the exception.
  3. Use the !analyze –v command to analyze the exceptions.
High CPU (or) Memory
  1. Collect performance counters along with the dump.
  2. Determine the thread running for a long time using the !runaway command.
  3. From performance counters, determine the thread spiking the CPU and analyze its stack trace.
  4. Analyze that thread's stack trace using the kp (or) !clrstack command.
    Analyze heap objects using the !dumpheap command.
  1. Collect 2-3 sets of dumps with an interval of 4-5 seconds.
  2. Determine the progress of the thread running in each dump from its stack trace. This will helps us to determine whether a thread hang/waiting on something like a DB connection, lock, and so on.
  3. Check for any locks using the !SyncBlk (or) !locks command.