Looking inside a .NET core process using windbg


In this blog post,we are going to look inside of a .NET Core process using windbg. .NET CORE process footprint is as minimal as possible so with this blog post,we are going to look at a simple .net core concole app running (simplest console app with bare minimum managed code) and check

  • How many .NET Objects it needs to run a console application
  • .NET dlls (managed) are loaded for a simple console application
  • What are the threads running (managed and unmanaged or native)
  • How does the callstack look like for .NET threads
  • How to look for a particular .NET object and dump it details

First lets start a simple .NET core console application .I already have the .NET core SDK installed .Now create a simple console app and run

D:\PROJECTS\dotnet>dotnet new console
The template "Console Application" was created successfully.

Processing post-creation actions...
Running 'dotnet restore' on D:\PROJECTS\dotnet\dotnet.csproj...
 Restoring packages for D:\PROJECTS\dotnet\dotnet.csproj...
 Generating MSBuild file D:\PROJECTS\dotnet\obj\dotnet.csproj.nuget.g.props.
 Generating MSBuild file D:\PROJECTS\dotnet\obj\dotnet.csproj.nuget.g.targets.
 Restore completed in 704.29 ms for D:\PROJECTS\dotnet\dotnet.csproj.

Restore succeeded.

After this ,We can do a build and run

D:\PROJECTS\dotnet>dotnet build
Microsoft (R) Build Engine version 15.5.180.51428 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

Restore completed in 57.84 ms for D:\PROJECTS\dotnet\dotnet.csproj.
 dotnet -> D:\PROJECTS\dotnet\bin\Debug\netcoreapp2.0\dotnet.dll

Build succeeded.
 0 Warning(s)
 0 Error(s)

Time Elapsed 00:00:06.06

Finally running the app

D:\PROJECTS\dotnet>dotnet run
Hello World!

We are going to use a windbg tool to do this,you can install debugging tools for windows to get windbg .If you are doing a fresh installation, Make sure to install As a standalone tool set

If you want to download only Debugging Tools for Windows, install the Windows SDK, and, during the installation, select the Debugging Tools for Windows box and clear all the other boxes.

Once you have installed debugging tools,run windbg(make sure to run 64 bit version ). To inspect the dotnet process,we will make a small change to the code to add a Console.ReadLine(). This is done to make sure the process does not terminate as soon as it finishes

using System;

namespace dotnet
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
Console.ReadLine();
}
}
}
  1. Run the console app using dotnet run command
  2. When it successfully runs,it will launch console app and will not exit because of the Console.ReadLine() we added
  3.  Now,launch windg and attach to dotnet.exe process as shown below

make sure to launch windbg with the correct bitness(32 bit or 64 bit) .You have to match the bitness of the process you are going to debug with the windbg

Now from the windbg menu,choose Attach to a Process( press F6) and find dotnet.exe running.

Once you have attached,you should see following

Microsoft (R) Windows Debugger Version 6.12.0002.633 AMD64
 Copyright (c) Microsoft Corporation. All rights reserved.

*** wait with pending attach
 Symbol search path is: srv*c:\symcache*http://msdl.microsoft.com/download/symbols
 Executable search path is:
 ModLoad: 00000001`3fdc0000 00000001`3fde7000 C:\Program Files\dotnet\dotnet.exe
 ModLoad: 00000000`76e80000 00000000`7702a000 C:\windows\SYSTEM32\ntdll.dll
 ModLoad: 00000000`76c60000 00000000`76d7f000 C:\windows\system32\kernel32.dll
 ModLoad: 000007fe`fcbf0000 000007fe`fcc5a000 C:\windows\system32\KERNELBASE.dll
 ModLoad: 00000000`74860000 00000000`748ee000 C:\windows\System32\SYSFER.DLL
 ModLoad: 000007fe`fdb20000 000007fe`fdbfb000 C:\windows\system32\ADVAPI32.dll
 ModLoad: 000007fe`fea80000 000007fe`feb1f000 C:\windows\system32\msvcrt.dll
 ModLoad: 000007fe`fd310000 000007fe`fd32f000 C:\windows\SYSTEM32\sechost.dll
 ModLoad: 000007fe`feff0000 000007fe`ff11d000 C:\windows\system32\RPCRT4.dll
 ModLoad: 000007fe`f5430000 000007fe`f5434000 C:\windows\system32\api-ms-win-crt-runtime-l1-1-0.dll
 ModLoad: 000007fe`dee30000 000007fe`def24000 C:\windows\system32\ucrtbase.DLL
 ModLoad: 000007fe`f5420000 000007fe`f5423000 C:\windows\system32\api-ms-win-core-timezone-l1-1-0.dll
 ModLoad: 000007fe`f4410000 000007fe`f4413000 C:\windows\system32\api-ms-win-core-file-l2-1-0.dll
 ModLoad: 000007fe`f4400000 000007fe`f4403000 C:\windows\system32\api-ms-win-core-localization-l1-2-0.dll
 ModLoad: 000007fe`fba40000 000007fe`fba43000 C:\windows\system32\api-ms-win-core-synch-l1-2-0.dll
 ModLoad: 000007fe`f4360000 000007fe`f4363000 C:\windows\system32\api-ms-win-core-processthreads-l1-1-1.dll
 ModLoad: 000007fe`f4350000 000007fe`f4353000 C:\windows\system32\api-ms-win-core-file-l1-2-0.dll
 ModLoad: 000007fe`ea900000 000007fe`ea905000 C:\windows\system32\api-ms-win-crt-math-l1-1-0.dll
 ModLoad: 000007fe`f4100000 000007fe`f4103000 C:\windows\system32\api-ms-win-crt-heap-l1-1-0.dll
 ModLoad: 000007fe`ee870000 000007fe`ee874000 C:\windows\system32\api-ms-win-crt-convert-l1-1-0.dll
 ModLoad: 000007fe`f40f0000 000007fe`f40f4000 C:\windows\system32\api-ms-win-crt-stdio-l1-1-0.dll
 ModLoad: 000007fe`f42f0000 000007fe`f42f4000 C:\windows\system32\api-ms-win-crt-string-l1-1-0.dll
 ModLoad: 000007fe`ee620000 000007fe`ee623000 C:\windows\system32\api-ms-win-crt-locale-l1-1-0.dll
 ModLoad: 000007fe`ea8f0000 000007fe`ea8f5000 C:\windows\system32\api-ms-win-crt-multibyte-l1-1-0.dll
 ModLoad: 000007fe`d6b00000 000007fe`d6b51000 C:\Program Files\dotnet\host\fxr\2.0.5\hostfxr.dll
 ModLoad: 000007fe`e77e0000 000007fe`e77e3000 C:\windows\system32\api-ms-win-crt-filesystem-l1-1-0.dll
 ModLoad: 000007fe`d6a70000 000007fe`d6af9000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\hostpolicy.dll
 ModLoad: 000007fe`d1070000 000007fe`d15ba000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\coreclr.dll
 ModLoad: 000007fe`fd640000 000007fe`fd83c000 C:\windows\system32\ole32.dll
 ModLoad: 000007fe`ff120000 000007fe`ff187000 C:\windows\system32\GDI32.dll
 ModLoad: 00000000`76d80000 00000000`76e7a000 C:\windows\system32\USER32.dll
 ModLoad: 000007fe`fd3d0000 000007fe`fd3de000 C:\windows\system32\LPK.dll
 ModLoad: 000007fe`fd3e0000 000007fe`fd4ab000 C:\windows\system32\USP10.dll
 ModLoad: 000007fe`fe990000 000007fe`fea6a000 C:\windows\system32\OLEAUT32.dll
 ModLoad: 000007fe`fbc20000 000007fe`fbc2c000 C:\windows\system32\VERSION.dll
 ModLoad: 000007fe`fd290000 000007fe`fd301000 C:\windows\system32\SHLWAPI.dll
 ModLoad: 000007fe`fc4b0000 000007fe`fc4d2000 C:\windows\system32\bcrypt.dll
 ModLoad: 000007fe`de290000 000007fe`de293000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\api-ms-win-crt-utility-l1-1-0.dll
 ModLoad: 000007fe`ddb80000 000007fe`ddb83000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\api-ms-win-crt-time-l1-1-0.dll
 ModLoad: 000007fe`fd260000 000007fe`fd28e000 C:\windows\system32\IMM32.DLL
 ModLoad: 000007fe`fd4b0000 000007fe`fd5b9000 C:\windows\system32\MSCTF.dll
 ModLoad: 000007fe`c5330000 000007fe`c5e84000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\System.Private.CoreLib.dll
 ModLoad: 000007fe`f3ae0000 000007fe`f3b4f000 C:\windows\SYSTEM32\MSCOREE.DLL
 ModLoad: 00000000`00300000 00000000`00308000 D:\PROJECTS\dotnet\bin\Debug\netcoreapp2.0\dotnet.dll
 ModLoad: 000007fe`ddb70000 000007fe`ddb7d000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\System.Runtime.dll
 ModLoad: 000007fe`d1bb0000 000007fe`d1cbb000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\clrjit.dll
 ModLoad: 000007fe`d0e60000 000007fe`d0e87000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\System.Console.dll
 ModLoad: 000007fe`dc4e0000 000007fe`dc4f3000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\System.Threading.dll
 ModLoad: 000007fe`d1cc0000 000007fe`d1d34000 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\System.Runtime.Extensions.dll
 (6018.7540): Break instruction exception - code 80000003 (first chance)

This means that windbg is successfully attached to our dotnet core process.

Now we can run some commands in windbg to get some internal details about

Getting the active threads running

For this run a simple command ~ in windbg

0:000> ~
 . 0 Id: 6018.1244 Suspend: 1 Teb: 000007ff`fffde000 Unfrozen
 1 Id: 6018.67e8 Suspend: 1 Teb: 000007ff`fffdc000 Unfrozen
 2 Id: 6018.550 Suspend: 1 Teb: 000007ff`fffda000 Unfrozen
 # 3 Id: 6018.7540 Suspend: 1 Teb: 000007ff`fffd8000 Unfrozen

tilde(~) simply lists all the threads running with the threadid.There are many variations you can do

  • ~*  - shows little more information like the top method currently executing .* means all the threads
  • ~*k - shows all the threads along with the stack
  • ~<threadnum>s - will switch to thread number threadnum you specifiy
    • e.g. 0:000> ~1s
       ntdll!ZwWaitForMultipleObjects+0xa:
       00000000`76ecc2ea c3 ret
       0:001>
0:001> ~*k

0 Id: 6018.1244 Suspend: 1 Teb: 000007ff`fffde000 Unfrozen
 Child-SP RetAddr Call Site
 00000000`001adc48 00000000`76c818e8 ntdll!NtRequestWaitReplyPort+0xa
 00000000`001adc50 00000000`76cb57f1 kernel32!ConsoleClientCallServer+0x54
 00000000`001adc80 00000000`76cca9f2 kernel32!ReadConsoleInternal+0x1f1
 00000000`001addd0 00000000`76c97e64 kernel32!ReadConsoleA+0xb2
 00000000`001adeb0 000007fe`716d147f kernel32!TlsGetValue+0x81fe
 00000000`001adef0 000007fe`d0e78f65 0x7fe`716d147f
 00000000`001adfb0 000007fe`d0e78db3 System_Console+0x18f65
 00000000`001ae010 000007fe`d1d0dc6d System_Console+0x18db3
 00000000`001ae080 000007fe`d1d0e04a System_Runtime_Extensions+0x4dc6d
 00000000`001ae0d0 000007fe`d0e7d517 System_Runtime_Extensions+0x4e04a
 00000000`001ae120 000007fe`d0e752fa System_Console+0x1d517
 00000000`001ae170 000007fe`716d04b6 System_Console+0x152fa
 00000000`001ae1a0 000007fe`d11a35d3 0x7fe`716d04b6
 00000000`001ae1e0 000007fe`d10cd9bf coreclr!CallDescrWorkerInternal+0x83 [E:\A\_work\1791\s\src\vm\amd64\CallDescrWorkerAMD64.asm @ 101]
 00000000`001ae220 000007fe`d1193ef7 coreclr!MethodDescCallSite::CallTargetWorker+0x17b [e:\a\_work\1791\s\src\vm\callhelpers.cpp @ 653]
 00000000`001ae370 000007fe`d108b195 coreclr!RunMain+0x17f [e:\a\_work\1791\s\src\vm\assembly.cpp @ 1849]
 00000000`001ae5d0 000007fe`d112ba29 coreclr!Assembly::ExecuteMainMethod+0xb5 [e:\a\_work\1791\s\src\vm\assembly.cpp @ 1944]
 00000000`001ae890 000007fe`d112d9ce coreclr!CorHost2::ExecuteAssembly+0x149 [e:\a\_work\1791\s\src\vm\corhost.cpp @ 502]
 00000000`001ae960 000007fe`d6a8e8b9 coreclr!coreclr_execute_assembly+0xde [e:\a\_work\1791\s\src\dlls\mscoree\unixinterface.cpp @ 407]
 00000000`001ae9f0 000007fe`d6a8ee44 hostpolicy!run+0xdb9
 00000000`001af0c0 000007fe`d6b19b05 hostpolicy!corehost_main+0x164
 00000000`001af240 000007fe`d6b1f42b hostfxr!execute_app+0x1f5
 00000000`001af310 000007fe`d6b1e819 hostfxr!fx_muxer_t::read_config_and_execute+0x94b
 00000000`001af9b0 000007fe`d6b1cc8d hostfxr!fx_muxer_t::parse_args_and_execute+0x409
 00000000`001afb40 00000001`3fdc9abc hostfxr!fx_muxer_t::execute+0x22d
 00000000`001afcd0 00000001`3fdce099 dotnet!wmain+0x46c
 00000000`001afde0 00000000`76c759cd dotnet!__scrt_common_main_seh+0x11d [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 253]
 00000000`001afe20 00000000`76eaa561 kernel32!BaseThreadInitThunk+0xd
 00000000`001afe50 00000000`00000000 ntdll!RtlUserThreadStart+0x1d

1 Id: 6018.67e8 Suspend: 1 Teb: 000007ff`fffdc000 Unfrozen
 Child-SP RetAddr Call Site
 00000000`0232f648 000007fe`fcbf1430 ntdll!ZwWaitForMultipleObjects+0xa
 00000000`0232f650 00000000`76c816e3 KERNELBASE!WaitForMultipleObjectsEx+0xe8
 00000000`0232f750 000007fe`d118b36a kernel32!WaitForMultipleObjectsExImplementation+0xb3
 00000000`0232f7e0 000007fe`d118b44e coreclr!DebuggerRCThread::MainLoop+0xce [e:\a\_work\1791\s\src\debug\ee\rcthread.cpp @ 1241]
 00000000`0232f8a0 000007fe`d118ae8a coreclr!DebuggerRCThread::ThreadProc+0xd2 [e:\a\_work\1791\s\src\debug\ee\rcthread.cpp @ 1042]
 00000000`0232f8f0 00000000`76c759cd coreclr!DebuggerRCThread::ThreadProcStatic+0x1a [e:\a\_work\1791\s\src\debug\ee\rcthread.cpp @ 1642]
 00000000`0232f920 00000000`76eaa561 kernel32!BaseThreadInitThunk+0xd
 00000000`0232f950 00000000`00000000 ntdll!RtlUserThreadStart+0x1d

2 Id: 6018.550 Suspend: 1 Teb: 000007ff`fffda000 Unfrozen
 Child-SP RetAddr Call Site
 00000000`1a94f5f8 000007fe`fcbf1430 ntdll!ZwWaitForMultipleObjects+0xa
 00000000`1a94f600 00000000`76c816e3 KERNELBASE!WaitForMultipleObjectsEx+0xe8
 00000000`1a94f700 000007fe`d1176361 kernel32!WaitForMultipleObjectsExImplementation+0xb3
 00000000`1a94f790 000007fe`d1175de2 coreclr!FinalizerThread::WaitForFinalizerEvent+0x85 [e:\a\_work\1791\s\src\vm\finalizerthread.cpp @ 469]
 00000000`1a94f7d0 000007fe`d10cd66b coreclr!FinalizerThread::FinalizerThreadWorker+0x62 [e:\a\_work\1791\s\src\vm\finalizerthread.cpp @ 587]
 00000000`1a94f830 000007fe`d10cd586 coreclr!ManagedThreadBase_DispatchInner+0x43 [e:\a\_work\1791\s\src\vm\threads.cpp @ 9204]
 00000000`1a94f870 000007fe`d10cd498 coreclr!ManagedThreadBase_DispatchMiddle+0x82 [e:\a\_work\1791\s\src\vm\threads.cpp @ 9253]
 00000000`1a94f9d0 000007fe`d117587c coreclr!ManagedThreadBase_DispatchOuter+0xb4 [e:\a\_work\1791\s\src\vm\threads.cpp @ 9492]
 00000000`1a94fa80 000007fe`d11773fb coreclr!FinalizerThread::FinalizerThreadStart+0x9c [e:\a\_work\1791\s\src\vm\finalizerthread.cpp @ 774]
 00000000`1a94fb20 00000000`76c759cd coreclr!Thread::intermediateThreadProc+0x8b [e:\a\_work\1791\s\src\vm\threads.cpp @ 2594]
 00000000`1a94fbe0 00000000`76eaa561 kernel32!BaseThreadInitThunk+0xd
 00000000`1a94fc10 00000000`00000000 ntdll!RtlUserThreadStart+0x1d

# 3 Id: 6018.7540 Suspend: 1 Teb: 000007ff`fffd8000 Unfrozen
 Child-SP RetAddr Call Site
 00000000`1ac7fc28 00000000`76f72e08 ntdll!DbgBreakPoint
 00000000`1ac7fc30 00000000`76c759cd ntdll!DbgUiRemoteBreakin+0x38
 00000000`1ac7fc60 00000000`76eaa561 kernel32!BaseThreadInitThunk+0xd
 00000000`1ac7fc90 00000000`00000000 ntdll!RtlUserThreadStart+0x1d

We see 4 threads running in idle state and callstacks of the threads.But these windbg commands only shows native stacks and does not show managed threads or stacks.To make windbg understand about CLR and managed threads, we have to windbg debugging extension dlls  .In this case we are going to use a dll called SOS

We have SOS.dll for every version and bitness of .NET framework (.NET 1.1,2.0,4.0 etc) .So for .NET core process debugging we need to use .NET Core's sos.dll . And the good part is that sos.dll is shipped with the dotnet and you will find it on

64bit: C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\sos.dll 

32bit: C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\2.0.5\sos.dll

Now to load any extension to windbg,we have to use .load command

.load C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\sos

You can also use alternate command .loadby

0:001> .loadby sos coreclr

What this does is it will automatically find the sos path and load from the already existing dll  coreclr which is loaded into the dotnet.exe process. Once it is loaded,you can get all the commands using help

0:001> !help
 -------------------------------------------------------------------------------
 SOS is a debugger extension DLL designed to aid in the debugging of managed
 programs. Functions are listed by category, then roughly in order of
 importance. Shortcut names for popular functions are listed in parenthesis.
 Type "!help <functionname>" for detailed info on that function.

Object Inspection Examining code and stacks
 ----------------------------- -----------------------------
 DumpObj (do) Threads
 DumpArray (da) ThreadState
 DumpStackObjects (dso) IP2MD
 DumpHeap U
 DumpVC DumpStack
 GCRoot EEStack
 ObjSize CLRStack
 FinalizeQueue GCInfo
 PrintException (pe) EHInfo
 TraverseHeap BPMD
 COMState

Examining CLR data structures Diagnostic Utilities
 ----------------------------- -----------------------------
 DumpDomain VerifyHeap
 EEHeap VerifyObj
 Name2EE FindRoots
 SyncBlk HeapStat
 DumpMT GCWhere
 DumpClass ListNearObj (lno)
 DumpMD GCHandles
 Token2EE GCHandleLeaks
 EEVersion FinalizeQueue (fq)
 DumpModule FindAppDomain
 ThreadPool SaveModule
 DumpAssembly ProcInfo
 DumpSigElem StopOnException (soe)
 DumpRuntimeTypes DumpLog
 DumpSig VMMap
 RCWCleanupList VMStat
 DumpIL MinidumpMode
 DumpRCW AnalyzeOOM (ao)
 DumpCCW

Examining the GC history Other
 ----------------------------- -----------------------------
 HistInit FAQ
 HistRoot
 HistObj
 HistObjFind
 HistClear

don't worry about all these commands ,we are going to use a handful of them .mainly !threads !CLRStack and !dumpheap .

Please note that all extension commands will start with ! .So all commands inside sos.dll we have to use !threads ,!clrstack etc.

 

Getting managed threads and stacks

0:001> !threads
 ThreadCount: 2
 UnstartedThread: 0
 BackgroundThread: 1
 PendingThread: 0
 DeadThread: 0
 Hosted Runtime: no
 Lock
 ID OSID ThreadOBJ State GC Mode GC Alloc Context Domain Count Apt Exception
 0 1 1244 00000000005cb900 20020 Preemptive 0000000002355278:00000000023561C0 0000000000433400 1 Ukn
 2 2 550 00000000005f1fb0 21220 Preemptive 0000000000000000:0000000000000000 0000000000433400 0 Ukn (Finalizer)

Once you see manageed thread,you can switch to that thread by ~<threadnumber>s

to switch to first thread ~ss

0:001> ~0s
 ntdll!NtRequestWaitReplyPort+0xa:
 00000000`76ecbf5a c3 ret
 0:000> !clrstack
 OS Thread Id: 0x1244 (0)
 Child SP IP Call Site
 00000000001adf20 0000000076ecbf5a [InlinedCallFrame: 00000000001adf20] Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr)
 00000000001adf20 000007fe716d147f [InlinedCallFrame: 00000000001adf20] Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr)
 00000000001adef0 000007fe716d147f DomainBoundILStubClass.IL_STUB_PInvoke(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr)
 00000000001adfb0 000007fed0e78f65 System.ConsolePal+WindowsConsoleStream.ReadFileNative(IntPtr, Byte[], Int32, Int32, Boolean, Int32 ByRef, Boolean) [E:\A\_work\1439\s\corefx\src\System.Console\src\System\ConsolePal.Windows.cs @ 1170]
 00000000001ae010 000007fed0e78db3 System.ConsolePal+WindowsConsoleStream.Read(Byte[], Int32, Int32) [E:\A\_work\1439\s\corefx\src\System.Console\src\System\ConsolePal.Windows.cs @ 1121]
 00000000001ae080 000007fed1d0dc6d System.IO.StreamReader.ReadBuffer() [E:\A\_work\1439\s\corefx\src\System.Runtime.Extensions\src\System\IO\StreamReader.cs @ 627]
 00000000001ae0d0 000007fed1d0e04a System.IO.StreamReader.ReadLine() [E:\A\_work\1439\s\corefx\src\System.Runtime.Extensions\src\System\IO\StreamReader.cs @ 802]
 00000000001ae120 000007fed0e7d517 System.IO.SyncTextReader.ReadLine() [E:\A\_work\1439\s\corefx\src\System.Console\src\System\IO\SyncTextReader.cs @ 78]
 00000000001ae170 000007fed0e752fa System.Console.ReadLine() [E:\A\_work\1439\s\corefx\src\System.Console\src\System\Console.cs @ 474]
 00000000001ae1a0 000007fe716d04b6 dotnet.Program.Main(System.String[]) [D:\PROJECTS\dotnet\Program.cs @ 10]
 00000000001ae418 000007fed11a35d3 [GCFrame: 00000000001ae418]
 00000000001ae8f8 000007fed11a35d3 [GCFrame: 00000000001ae8f8]

Now We can check how the native stack will look like by running k

0:000> k
Child-SP RetAddr Call Site
00000000`001adc48 00000000`76c818e8 ntdll!NtRequestWaitReplyPort+0xa
00000000`001adc50 00000000`76cb57f1 kernel32!ConsoleClientCallServer+0x54
00000000`001adc80 00000000`76cca9f2 kernel32!ReadConsoleInternal+0x1f1
00000000`001addd0 00000000`76c97e64 kernel32!ReadConsoleA+0xb2
00000000`001adeb0 000007fe`716d147f kernel32!TlsGetValue+0x81fe
00000000`001adef0 000007fe`d0e78f65 0x7fe`716d147f
00000000`001adfb0 000007fe`d0e78db3 System_Console+0x18f65
00000000`001ae010 000007fe`d1d0dc6d System_Console+0x18db3
00000000`001ae080 000007fe`d1d0e04a System_Runtime_Extensions+0x4dc6d
00000000`001ae0d0 000007fe`d0e7d517 System_Runtime_Extensions+0x4e04a
00000000`001ae120 000007fe`d0e752fa System_Console+0x1d517
00000000`001ae170 000007fe`716d04b6 System_Console+0x152fa
00000000`001ae1a0 000007fe`d11a35d3 0x7fe`716d04b6
00000000`001ae1e0 000007fe`d10cd9bf coreclr!CallDescrWorkerInternal+0x83 [E:\A\_work\1791\s\src\vm\amd64\CallDescrWorkerAMD64.asm @ 101]
00000000`001ae220 000007fe`d1193ef7 coreclr!MethodDescCallSite::CallTargetWorker+0x17b [e:\a\_work\1791\s\src\vm\callhelpers.cpp @ 653]
00000000`001ae370 000007fe`d108b195 coreclr!RunMain+0x17f [e:\a\_work\1791\s\src\vm\assembly.cpp @ 1849]
00000000`001ae5d0 000007fe`d112ba29 coreclr!Assembly::ExecuteMainMethod+0xb5 [e:\a\_work\1791\s\src\vm\assembly.cpp @ 1944]
00000000`001ae890 000007fe`d112d9ce coreclr!CorHost2::ExecuteAssembly+0x149 [e:\a\_work\1791\s\src\vm\corhost.cpp @ 502]
00000000`001ae960 000007fe`d6a8e8b9 coreclr!coreclr_execute_assembly+0xde [e:\a\_work\1791\s\src\dlls\mscoree\unixinterface.cpp @ 407]
00000000`001ae9f0 000007fe`d6a8ee44 hostpolicy!run+0xdb9
00000000`001af0c0 000007fe`d6b19b05 hostpolicy!corehost_main+0x164
00000000`001af240 000007fe`d6b1f42b hostfxr!execute_app+0x1f5
00000000`001af310 000007fe`d6b1e819 hostfxr!fx_muxer_t::read_config_and_execute+0x94b
00000000`001af9b0 000007fe`d6b1cc8d hostfxr!fx_muxer_t::parse_args_and_execute+0x409
00000000`001afb40 00000001`3fdc9abc hostfxr!fx_muxer_t::execute+0x22d
00000000`001afcd0 00000001`3fdce099 dotnet!wmain+0x46c
00000000`001afde0 00000000`76c759cd dotnet!__scrt_common_main_seh+0x11d [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 253]
00000000`001afe20 00000000`76eaa561 kernel32!BaseThreadInitThunk+0xd
00000000`001afe50 00000000`00000000 ntdll!RtlUserThreadStart+0x1d

 

As you see the managed stack and native stack look different this is because CLR abstracts away many details from the actual machine level execution.

hostfxr!execute_app method executes your .NET code. Once it loads coreclr ,everything happens is on .NET terms . coreclr loads the .NET dlls and all the reference dlls and execute your code

As you see there are two managed threads running (from the output of !threads command),lets see what the other thread is doing

0:000> ~2s
 ntdll!ZwWaitForMultipleObjects+0xa:
 00000000`76ecc2ea c3 ret
 0:002> !clrstack
 OS Thread Id: 0x550 (2)
 Child SP IP Call Site
 000000001a94fa00 0000000076ecc2ea [DebuggerU2MCatchHandlerFrame: 000000001a94fa00]

We really do not see any manage callstack although it is managed thread.So let's see what it actually is by looking at the native callstack

0:002> k
 Child-SP RetAddr Call Site
 00000000`1a94f5f8 000007fe`fcbf1430 ntdll!ZwWaitForMultipleObjects+0xa
 00000000`1a94f600 00000000`76c816e3 KERNELBASE!WaitForMultipleObjectsEx+0xe8
 00000000`1a94f700 000007fe`d1176361 kernel32!WaitForMultipleObjectsExImplementation+0xb3
 00000000`1a94f790 000007fe`d1175de2 coreclr!FinalizerThread::WaitForFinalizerEvent+0x85 [e:\a\_work\1791\s\src\vm\finalizerthread.cpp @ 469]
 00000000`1a94f7d0 000007fe`d10cd66b coreclr!FinalizerThread::FinalizerThreadWorker+0x62 [e:\a\_work\1791\s\src\vm\finalizerthread.cpp @ 587]
 00000000`1a94f830 000007fe`d10cd586 coreclr!ManagedThreadBase_DispatchInner+0x43 [e:\a\_work\1791\s\src\vm\threads.cpp @ 9204]
 00000000`1a94f870 000007fe`d10cd498 coreclr!ManagedThreadBase_DispatchMiddle+0x82 [e:\a\_work\1791\s\src\vm\threads.cpp @ 9253]
 00000000`1a94f9d0 000007fe`d117587c coreclr!ManagedThreadBase_DispatchOuter+0xb4 [e:\a\_work\1791\s\src\vm\threads.cpp @ 9492]
 00000000`1a94fa80 000007fe`d11773fb coreclr!FinalizerThread::FinalizerThreadStart+0x9c [e:\a\_work\1791\s\src\vm\finalizerthread.cpp @ 774]
 00000000`1a94fb20 00000000`76c759cd coreclr!Thread::intermediateThreadProc+0x8b [e:\a\_work\1791\s\src\vm\threads.cpp @ 2594]
 00000000`1a94fbe0 00000000`76eaa561 kernel32!BaseThreadInitThunk+0xd
 00000000`1a94fc10 00000000`00000000 ntdll!RtlUserThreadStart+0x1d

As you see from the stack,it is finalizer thread

Now let's move on to  .NET obejcts in the heap.For this ,we will use !dumpheap .

0:002> !dumpheap
 Statistics:
 MT Count TotalSize Class Name
 000007fec5cd6c68 1 24 System.Collections.Generic.GenericEqualityComparer`1[[System.Char, System.Private.CoreLib]]
 000007fec5ccb060 1 24 System.Environment+<>c
 000007fec5cc5130 1 24 System.Collections.Generic.GenericEqualityComparer`1[[System.String, System.Private.CoreLib]]
 000007fec5cbe1e0 1 24 System.Reflection.Missing
 000007fec5cb8c58 1 24 System.Security.Policy.ApplicationTrust
 000007fec5cb6e98 1 24 System.Diagnostics.Tracing.EtwEventProvider
 000007fec5cb4168 1 24 System.OrdinalIgnoreCaseComparer
 000007fec5cb4068 1 24 System.OrdinalCaseSensitiveComparer
 000007fec5cb1bd8 1 24 System.SharedStatics
 000007fec5ca00f8 1 24 System.WeakReference
 000007fec5c91228 1 24 System.Collections.Generic.NonRandomizedStringEqualityComparer
 000007fec5c88388 1 24 System.Boolean
 000007fec5c53388 1 24 System.Attribute[]
 000007fec537f038 1 24 System.Collections.Generic.Dictionary`2+KeyCollection[[System.String, System.Private.CoreLib],[System.Object, System.Private.CoreLib]]
 000007fe7157cdb8 1 24 System.IO.SyncTextReader
 000007fe715790d8 1 24 System.Console+<>c
 000007fe71566fe0 1 24 System.Collections.Generic.ObjectEqualityComparer`1[[System.RuntimeType, System.Private.CoreLib]]
 000007fec5c62708 1 26 System.Globalization.CalendarId[]
 000007fec5c53260 1 31 System.Boolean[]
 000007fec5ce2358 1 32 System.Buffers.TlsOverPerCoreLockedStacksArrayPool`1[[System.Char, System.Private.CoreLib]]
 000007fec5ccc430 1 32 System.IO.Stream+NullStream
 000007fec5c9d0a8 1 32 System.Diagnostics.Tracing.ActivityTracker
 000007fec5c8da20 1 32 System.Guid
 000007fec5c59028 1 32 System.Reflection.RuntimePropertyInfo[]
 000007fec5c98ef0 1 40 System.Collections.Generic.List`1+Enumerator[[System.String, System.Private.CoreLib]]
 000007fec5c54658 1 40 System.WeakReference[]
 000007fec5378e28 1 40 System.Collections.Generic.List`1[[System.WeakReference, System.Private.CoreLib]]
 000007fec5377168 1 40 System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]]
 000007fe7157bc50 1 40 System.IO.TextWriter+NullTextWriter
 000007fe715799e0 1 40 Interop+InputRecord
 000007fe71567680 1 40 System.Reflection.CerHashtable`2+Table[[System.String, System.Private.CoreLib],[System.Reflection.RuntimePropertyInfo[], System.Private.CoreLib]]
 000007fe715668c0 1 40 System.Collections.Generic.Dictionary`2+KeyCollection+Enumerator[[System.String, System.Private.CoreLib],[System.Object, System.Private.CoreLib]]
 000007fec5cce310 1 48 System.Text.Encoding+DefaultDecoder
 000007fec5c59768 2 48 System.Reflection.ParameterInfo[]
 000007fe7157c0f8 1 48 System.IO.SyncTextWriter
 000007fe7157be68 1 48 System.Text.OSEncoder
 000007fec5c92158 1 56 System.RuntimeType+RuntimeTypeCache+MemberInfoCache`1[[System.Reflection.RuntimePropertyInfo, System.Private.CoreLib]]
 000007fec5c91d58 1 56 System.RuntimeType+RuntimeTypeCache+MemberInfoCache`1[[System.Reflection.RuntimeMethodInfo, System.Private.CoreLib]]
 000007fec5c8f3e8 1 56 System.Reflection.RuntimeAssembly
 000007fec5c88d10 1 56 System.Globalization.CompareInfo
 000007fec5cb3f58 2 64 System.CultureAwareComparer
 000007fec5ca0e78 2 64 System.LazyHelper
 000007fec5c963c8 1 64 System.Reflection.RuntimeModule
 000007fec5c49988 1 64 Microsoft.Win32.UnsafeNativeMethods+ManifestEtw+EtwEnableCallback
 000007fe7157c6e0 1 64 System.Func`1[[System.IO.TextReader, System.Runtime.Extensions]]
 000007fe71579188 1 64 System.Func`1[[System.IO.TextWriter, System.Runtime.Extensions]]
 000007fe71567188 2 64 System.Diagnostics.Tracing.EventSourceAttribute[]
 000007fec5ca64e0 3 72 System.IntPtr
 000007fec5cb7070 2 80 System.Diagnostics.Tracing.EventSourceAttribute
 000007fec5c9d478 2 80 System.Lazy`1[[System.Boolean, System.Private.CoreLib]]
 000007fec537a308 1 80 System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib],[System.Globalization.CultureData, System.Private.CoreLib]]
 000007fec53799f0 1 80 System.Collections.Generic.Dictionary`2[[System.RuntimeType, System.Private.CoreLib],[System.RuntimeType, System.Private.CoreLib]]
 000007fe715677c8 1 80 System.Reflection.RuntimePropertyInfo[][]
 000007fec5cce920 2 96 System.Text.UTF8Encoding+UTF8EncodingSealed
 000007fec5ccb5e8 1 96 System.Diagnostics.Tracing.EventSource+OverideEventProvider
 000007fec5c587e0 2 96 System.Reflection.CustomAttributeRecord[]
 000007fec5c54280 3 96 System.IntPtr[]
 000007fe7157cbc0 1 96 System.IO.StreamReader
 000007fe715662b8 1 96 System.Collections.Generic.Dictionary`2+Entry[[System.String, System.Private.CoreLib],[System.Globalization.CultureData, System.Private.CoreLib]][]
 000007fec5c92b58 1 104 System.Reflection.RuntimePropertyInfo
 000007fe7157b9d0 1 104 System.IO.StreamWriter
 000007fec5cc38f0 2 112 System.Text.UnicodeEncoding
 000007fe7157b4b8 2 112 System.Text.ConsoleEncoding
 000007fe71579e10 2 112 System.ConsolePal+WindowsConsoleStream
 000007fec5c590b8 3 120 System.Reflection.RuntimeMethodInfo[]
 000007fec5c9ba08 4 128 System.Text.DecoderReplacementFallback
 000007fec5c9b9a8 4 128 System.Text.EncoderReplacementFallback
 000007fec5c8b930 2 128 System.Globalization.TextInfo
 000007fec5c44c10 2 128 System.Func`1[[System.Boolean, System.Private.CoreLib]]
 000007fe7157b0a0 2 128 System.Text.OSEncoding
 000007fe71567c28 2 128 System.Func`1[[System.Text.Encoding, System.Private.CoreLib]]
 000007fec5cb81b0 1 152 System.Buffers.ArrayPoolEventSource
 000007fec5cb3db8 1 152 System.StackOverflowException
 000007fec5cb2f68 1 152 System.ExecutionEngineException
 000007fec5ca5ba0 1 152 System.OutOfMemoryException
 000007fec5c8a718 1 152 System.Exception
 000007fec5c88340 1 152 System.AppDomain
 000007fec5cc2cb8 4 160 System.Text.InternalEncoderBestFitFallback
 000007fec5c90d98 1 160 System.Globalization.CalendarData
 000007fec5c6d230 1 160 System.Char[][]
 000007fec5c55b50 1 160 System.Buffers.TlsOverPerCoreLockedStacksArrayPool`1+PerCoreLockedStacks[[System.Char, System.Private.CoreLib]][]
 000007fec5c8af30 7 168 System.Object
 000007fec5cb19e8 2 176 System.RuntimeMethodInfoStub
 0000000000483380 7 186 Free
 000007fec5cc2770 4 192 System.Text.InternalDecoderBestFitFallback
 000007fec5c8b5a0 4 192 System.Text.StringBuilder
 000007fec5c2fba8 3 192 System.Reflection.MemberFilter
 000007fec5c923c0 2 208 System.Reflection.RuntimeMethodInfo
 000007fec5c61260 1 208 System.Globalization.CalendarData[]
 000007fec5c54ec8 7 216 System.Type[]
 000007fec5c96bd8 3 240 System.Signature
 000007fe71566b68 1 288 System.Collections.Generic.Dictionary`2+Entry[[System.RuntimeType, System.Private.CoreLib],[System.RuntimeType, System.Private.CoreLib]][]
 000007fec5cb9c80 2 304 System.Threading.ThreadAbortException
 000007fec5c91cb8 2 304 System.RuntimeType+RuntimeTypeCache
 000007fec5c9c190 3 312 System.AppDomainSetup
 000007fec5379db0 4 320 System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib],[System.Object, System.Private.CoreLib]]
 000007fec5c88be8 3 336 System.Globalization.CultureInfo
 000007fec5c546f8 1 364 System.UInt32[]
 000007fec5c53e28 10 384 System.RuntimeType[]
 000007fec5c54158 13 940 System.Int32[]
 000007fec5c8b498 2 944 System.Globalization.CultureData
 000007fe71566648 6 1008 System.Collections.Generic.Dictionary`2+Entry[[System.String, System.Private.CoreLib],[System.Object, System.Private.CoreLib]][]
 000007fec5c8dd70 36 1440 System.RuntimeType
 000007fec5c528e8 24 1728 System.String[]
 000007fec5c53050 7 4148 System.Byte[]
 000007fec5c52ca8 10 17776 System.Object[]
 000007fec5c567e0 14 31538 System.Char[]
 000007fec5c87be8 320 94632 System.String

 

We see that there are around 600 objects. We can get more details about !dumpheap by getting the help with help command

0:002> !help  dumpheap0:002> !help  dumpheap-------------------------------------------------------------------------------!DumpHeap [-stat]           [-strings]           [-short]          [-min <size>]           [-max <size>]           [-live]          [-dead]          [-thinlock]           [-startAtLowerBound]          [-mt <MethodTable address>]           [-type <partial type name>]           [start [end]]
!DumpHeap is a powerful command that traverses the garbage collected heap, collection statistics about objects. With it's various options, it can look forparticular types, restrict to a range, or look for ThinLocks (see !SyncBlk documentation). Finally, it will provide a warning if it detects excessive fragmentation in the GC heap. 
When called without options, the output is first a list of objects in the heap,followed by a report listing all the types found, their size and number:
 0:000> !dumpheap Address       MT     Size 00a71000 0015cde8       12 Free 00a7100c 0015cde8       12 Free 00a71018 0015cde8       12 Free 00a71024 5ba58328       68 00a71068 5ba58380       68 00a710ac 5ba58430       68 00a710f0 5ba5dba4       68 ... total 619 objects Statistics:       MT    Count TotalSize Class Name 5ba7607c        1        12 System.Security.Permissions.HostProtectionResource 5ba75d54        1        12 System.Security.Permissions.SecurityPermissionFlag 5ba61f18        1        12 System.Collections.CaseInsensitiveComparer ... 0015cde8        6     10260      Free 5ba57bf8      318     18136 System.String ...
"Free" objects are simply regions of space the garbage collector can use later.If 30% or more of the heap contains "Free" objects, the process may suffer fromheap fragmentation. This is usually caused by pinning objects for a long time combined with a high rate of allocation. Here is example output where !DumpHeapprovides a warning about fragmentation:
 <After the Statistics section> Fragmented blocks larger than 1MB:     Addr     Size Followed by 00a780c0    1.5MB    00bec800 System.Byte[] 00da4e38    1.2MB    00ed2c00 System.Byte[] 00f16df0    1.2MB    01044338 System.Byte[]
The arguments in detail:
-stat     Restrict the output to the statistical type summary-strings  Restrict the output to a statistical string value summary-short    Limits output to just the address of each object. This allows you          to easily pipe output from the command to another debugger           command for automation.-min      Ignore objects less than the size given in bytes-max      Ignore objects larger than the size given in bytes-live     Only print live objects-dead     Only print dead objects (objects which will be collected in the          next full GC)-thinlock Report on any ThinLocks (an efficient locking scheme, see !SyncBlk           documentation for more info)-startAtLowerBound           Force heap walk to begin at lower bound of a supplied address range.          (During plan phase, the heap is often not walkable because objects           are being moved. In this case, DumpHeap may report spurious errors,           in particular bad objects. It may be possible to traverse more of           the heap after the reported bad object. Even if you specify an           address range, !DumpHeap will start its walk from the beginning of           the heap by default. If it finds a bad object before the specified           range, it will stop before displaying the part of the heap in which           you are interested. This switch will force !DumpHeap to begin its           walk at the specified lower bound. You must supply the address of a           good object as the lower bound for this to work. Display memory at           the address of the bad object to manually find the next method           table (use !dumpmt to verify). If the GC is currently in a call to           memcopy, You may also be able to find the next object's address by           adding the size to the start address given as parameters.) -mt       List only those objects with the MethodTable given-type     List only those objects whose type name is a substring match of the           string provided. start     Begin listing from this addressend       Stop listing at this address
A special note about -type: Often, you'd like to find not only Strings, butSystem.Object arrays that are constrained to contain Strings. ("new String[100]" actually creates a System.Object array, but it can only holdSystem.String object pointers). You can use -type in a special way to findthese arrays. Just pass "-type System.String[]" and those Object arrays willbe returned. More generally, "-type <Substring of interesting type>[]".
The start/end parameters can be obtained from the output of !EEHeap -gc. For example, if you only want to list objects in the large heap segment:
 0:000> !eeheap -gc Number of GC Heaps: 1 generation 0 starts at 0x00c32754 generation 1 starts at 0x00c32748 generation 2 starts at 0x00a71000 segment    begin allocated     size 00a70000 00a71000  010443a8 005d33a8(6108072) Large object heap starts at 0x01a71000 segment    begin allocated     size 01a70000 01a71000  01a75000 0x00004000(16384) Total Size  0x5d73a8(6124456) ------------------------------ GC Heap Size  0x5d73a8(6124456)
 0:000> !dumpheap 1a71000 1a75000 Address       MT     Size 01a71000 5ba88bd8     2064 01a71810 0019fe48     2032 Free 01a72000 5ba88bd8     4096 01a73000 0019fe48     4096 Free 01a74000 5ba88bd8     4096 total 5 objects Statistics:       MT    Count TotalSize Class Name 0019fe48        2      6128      Free 5ba88bd8        3     10256 System.Object[] Total 5 objects
Finally, if GC heap corruption is present, you may see an error like this:
 0:000> !dumpheap -stat object 00a73d24: does not have valid MT curr_object : 00a73d24 Last good object: 00a73d14 ----------------
That indicates a serious problem. See the help for !VerifyHeap for more information on diagnosing the cause.

 

We can use DumpHeap command to look for memory leak issues in our application.


 

following are the different usecase of dumpheap command

  • To get all the strings loaded into our application
0:002> !dumpheap -strings
 00000000023313f0 000007fec5c87be8 26
 00000000023314c0 000007fec5c87be8 42
 0000000002331600 000007fec5c87be8 94
 0000000002331680 000007fec5c87be8 46
 00000000023316b0 000007fec5c87be8 74
 0000000002331700 000007fec5c87be8 40
 00000000023317e8 000007fec5c87be8 80
 0000000002331838 000007fec5c87be8 27448
 0000000002338370 000007fec5c87be8 84
 00000000023383c8 000007fec5c87be8 146
 0000000002338460 000007fec5c87be8 72
 00000000023384a8 000007fec5c87be8 68
 00000000023384f0 000007fec5c87be8 98
 0000000002338558 000007fec5c87be8 78
 00000000023385a8 000007fec5c87be8 112
 0000000002338618 000007fec5c87be8 70

===============trimmed=====================

42 1 HH:mm:ss
 42 1 November
 42 1 Saturday
 42 1 Thursday
 42 1 encoding
 42 1 hh:mm tt
 42 1 December
 42 1 February
 42 1 Infinity
 42 1 Internet
 42 1 JIT_PATH
 44 1 September
 44 1 FullTrust
 44 1 yyyy MMMM
 44 1 -Infinity
 44 1 APP_PATHS
 44 1 Wednesday
 46 1 MM/dd/yyyy
 46 1 yyyy-MM-dd
 48 1 MultiDomain
 50 1 NotSpecified
 50 1 FX_DEPS_FILE
 50 1 APP_NI_PATHS
 50 1 SingleDomain
 50 1 Hello World!
 56 1 MultiDomainHost
 60 1 Invariant Country
 62 1 Gregorian Calendar
 62 1 Invariant Language
 62 1 dddd, dd MMMM yyyy
 64 1 PROBING_DIRECTORIES
 64 1 LOADER_OPTIMIZATION
 66 1 ArrayPoolEventSource
 68 1 !x-sys-default-locale
 68 2 Name
 68 1 APP_LOCAL_WINMETADATA
 68 1 RFLCT_InvalidPropFail
 70 1 RFLCT_InvalidFieldFail
 70 1 APP_CONTEXT_DEPS_FILES
 72 2 en-us
 72 2 bytes
 72 2 chars
 78 1 APP_CONTEXT_BASE_DIRECTORY
 80 1 International Monetary Fund
 86 1 System.Globalization.Invariant
 88 2 charCount
 88 2 byteCount
 88 2 charIndex
 90 1 UseRandomizedStringHashAlgorithm
 92 2 dotnet.exe
 96 1 SYSTEM.BUFFERS.ARRAYPOOLEVENTSOURCE
 98 1 UseLatestBehaviorWhenTFMNotSpecified
 102 1 Invariant Language (Invariant Country)
 108 3 en-US
 112 1 D:\PROJECTS\dotnet\bin\Debug\netcoreapp2.0\
 122 1 System.Diagnostics.Eventing.FrameworkEventSource
 130 1 ERROR: Exception during construction of EventSource
 136 2 AppDomainCompatSwitch
 144 2 PLATFORM_RESOURCE_ROOTS
 146 1 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\;
 148 2 C:\Program Files\dotnet\
 160 2 TRUSTED_PLATFORM_ASSEMBLIES
 164 1 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\clrj
 168 1 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\msco
 168 2 NATIVE_DLL_SEARCH_DIRECTORIES
 174 1 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\Wind
 174 1 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\SOS.
 174 1 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\nets
 188 2 C:\Program Files\dotnet\dotnet.exe
 192 2 System.Buffers.ArrayPoolEventSource
 264 2 D:\PROJECTS\dotnet\bin\Debug\netcoreapp2.0\dotnet.dll
 298 1 C:\Program Files\dotnet\store\x64\netcoreapp2.0;C:\Users\rkolak
 326 1 D:\PROJECTS\dotnet\bin\Debug\netcoreapp2.0\dotnet.deps.json;C:\
 988 5 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\Micr
 29538 146 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\Syst
 54894 2 D:\PROJECTS\dotnet\bin\Debug\netcoreapp2.0\dotnet.dll;C:\Progra

You can get all the strings from the process e.g. your password stored as plaintext and stored in config if you are loading that into memory,you will be able to see it here.

  • To check the objects in LOH Large Object Heap

any objects which are more than 85000 bytes will be stored in Large Object Heap(LOH) and lot of objects in LOH can cause memory issues in your application.

0:002> !dumpheap -min 85000
Address MT Size

Statistics:
MT Count TotalSize Class Name
Total 0 objects

We did not get any large objects

  • How many objects are locked using lock statements
0:002> !dumpheap -thinlock
 Address MT Size
 0000000002355260 000007fe7157cdb8 24 ThinLock owner 1 (00000000005cb900) Recursive 0
 Found 1 objects.
0:002> !do 0000000002355260
 Name: System.IO.SyncTextReader
 MethodTable: 000007fe7157cdb8
 EEClass: 000007fe716cbc98
 Size: 24(0x18) bytes
 File: C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\System.Console.dll
 Fields:
 MT Field Offset Type VT Attr Value Name
 000007fe7157c520 40001a5 d0 System.IO.TextReader 0 static 0000000000000000 Null
 000007fe7157c520 400011c 8 System.IO.TextReader 0 instance 00000000023548a0 _in
 ThinLock owner 1 (00000000005cb900), Recursive 0
  • Dump all the objects of a particular type
0:002> !dumpheap -type Console
 Address MT Size
 00000000023530e0 000007fe715790d8 24
 0000000002353178 000007fe71579e10 56
 0000000002353330 000007fe7157b4b8 56
 0000000002354700 000007fe71579e10 56
 0000000002354810 000007fe7157b4b8 56

Statistics:
 MT Count TotalSize Class Name
 000007fe715790d8 1 24 System.Console+<>c
 000007fe7157b4b8 2 112 System.Text.ConsoleEncoding
 000007fe71579e10 2 112 System.ConsolePal+WindowsConsoleStream
 Total 5 objects

Dumping an object from process and looking at all properties

To get the details of any object,we will be using !DumpObject command.To this command,you have to pass the Object Address.Normally we use DumpObject command along with another command(dumpheap). We will first use dumpheap to find the address of a particular tpe of object and then use DumpObject(!do is alias) to further drill down

0:002> !dumpheap -type Console
 Address MT Size
 00000000023530e0 000007fe715790d8 24
 0000000002353178 000007fe71579e10 56
 0000000002353330 000007fe7157b4b8 56
 0000000002354700 000007fe71579e10 56
 0000000002354810 000007fe7157b4b8 56

Statistics:
 MT Count TotalSize Class Name
 000007fe715790d8 1 24 System.Console+<>c
 000007fe7157b4b8 2 112 System.Text.ConsoleEncoding
 000007fe71579e10 2 112 System.ConsolePal+WindowsConsoleStream
 Total 5 objects
 0:002> !do 00000000023530e0
 Name: System.Console+<>c
 MethodTable: 000007fe715790d8
 EEClass: 000007fe716cadc0
 Size: 24(0x18) bytes
 File: C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.5\System.Console.dll
 Fields:
 MT Field Offset Type VT Attr Value Name
 000007fe715790d8 4000044 60 System.Console+<>c 0 static 00000000023530e0 <>9
 000007fe7157c6e0 4000045 68 ...time.Extensions]] 0 static 00000000023546c0 <>9__13_0
 000007fe71567c28 4000046 70 ...Private.CoreLib]] 0 static 0000000002354738 <>9__15_0
 000007fe71567c28 4000047 78 ...Private.CoreLib]] 0 static 00000000023531b0 <>9__18_0
 000007fe71579188 4000048 80 ...time.Extensions]] 0 static 00000000023530f8 <>9__25_0
 000007fe71579188 4000049 88 ...time.Extensions]] 0 static 0000000000000000 <>9__27_0
 0000000000000000 400004a 90 0 static 0000000000000000 <>9__33_0
 0000000000000000 400004b 98 0 static 0000000000000000 <>9__35_0
 0000000000000000 400004c a0 0 static 0000000000000000 <>9__37_0
 000007fec5c701d8 400004d a8 ...Private.CoreLib]] 0 static 0000000000000000 <>9__151_0

 

In our next post we will explore looking inside a ASP.NET CORE process.We will also explore more detail  commands which can help you find memory leak inside a asp.net core process.

Comments (0)

Skip to main content