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(); } } }
- Run the console app using dotnet run command
- When it successfully runs,it will launch console app and will not exit because of the Console.ReadLine() we added
- 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.