.NET Diagnostics Tools: dump vs. gcdump

.NET Core 3.0 has introduced a new set of tools that allows runtime diagnostic that makes it easier to diagnose and solve performance or memory problems. dotnet-trace, dotnet-counters and dotnet-dump together make up the .NET Core runtime diagnostic tools and are grouped under GitHub in the dotnet/diagnostics repository, together with a bunch of documentation files. With .NET Core 3.1 Microsoft has added dotnet-gcdump to the collection of .NET Core runtime diagnostic tools.

Now you may wonder what the difference is between dotnet-dump and dotnet-gcdump? In this blog post i would like to show you the differences between dotnet-dump and dotnet-gcdump, as well as explain the use of the tools with an example.

Manage .NET Core tools

All .NET Core runtime diagnostic tools can be installed as .NET Core global tool and run from the commandline. The installation of these tools is really simple. Just open a terminal and use the dotnet tool install command:

$ dotnet tool install --global dotnet-<tool>

You can update the tool with dotnet tool update if its already installed

$ dotnet tool update --global dotnet-<tool>

Or simple trigger the removal with dotnet tool uninstall, if its not needed anymore

$ dotnet tool update --global dotnet-<tool>

Sample Application

The following small c# program reserves some memory and thus serves as a memory leak

class MyData {
    private int[] _data = new int[1024];
}

class Program {
    static readonly List<MyData> _data = new List<MyData>();
    public static void Main() {
        for (int i = 0; i < 1000000; i++) {
            _data.Add(new MyData());
        }
        Console.ReadLine();
    }
}

dotnet-dump

dotnet-dump provides a simple way to collect and analyze Windows and Linux process dumps (macOS is still unsupported). Now, run the sample program and open a new terminal. To get a list of all running .NET Core processes, you can use the dotnet dump ps command:

$ dotnet dump ps

13308 dotnet      'C:\Program Files\dotnet\dotnet.exe'
14180 dotnet      'C:\Program Files\dotnet\dotnet.exe'
1480 MemoryLeaker 'D:\dev\MemoryLeaker\MemoryLeaker\bin\Debug\netcoreapp3.1\MemoryLeaker.exe'

Next, a memory dump can be collected with the appropriate process id

$ dotnet dump collect --process-id 1480

Writing minidump with heap to 'C:\Users\stef\dump_20200417_220807.dmp'

You have several options for analyzing the memory dump. First, you can use the analyze parameter, followed by the dump file

$ dotnet dump analyze dump_20200417_220807.dmp

This brings up an interactive command processor that accepts SOS commands. SOS is a debugging extension that helps you debug managed programs. A list of all supported SOS commands can be found in the SOSCommand.cs file. See my blog post WinDbg Cheat Sheet for .NET Developers for further details.

On Linux-based operating systems, this is the only supported way. Under Windows, you can use PerfView or Visual Studio in addition to dotnet dump analyze.

The main problem with dotnet-dump is the lack of interobablity between Linux and Windows. That means, it is not possible to analyze memory dumps collected on Linux with Windows or vice versa.

dotnet-gcdump

dotnet-gcdump can be used on Linux, Mac, and Windows with runtime versions 3.1 or newer. With the help of dotnet-gcdump a heap dump of running .NET Core processes can be created. The dumps are created by triggering a garbage collection in the target process and turning on special events. Look at the DotNetHeapDumpGraphReader::SetupCallbacks method to find out, how to capture memory dumps in .NET using EventPipes.

Run the sample application again, and use the dotnet-gcdump ps command to find out what .NET processes are running, along with their process ID:

$ dotnet gcdump ps

Now, capture a gcdump with the dotnet-gcdump command with the collect and –process-id parameter. This can take several seconds depending on the size of the application:

$ dotnet gcdump collect --process-id 1480

Writing gcdump to 'D:\dev\20200407_055010_18984.gcdump'...
        Finished writing 153799 bytes.

Unlike dotnet-dump, the dumps created with dotnet-gcdump can be analyzed with PerfView or Visual Studio, regardless of whether the process was running on Linux, macOS or Windows. This means, whenever you dump the gc heap with dotnet-gcdump, you must have a running windows machine to analyze the dump.

Note: Opening a .gcdump on non-Windows platforms is currently not supported.

Conclusion

Use dotnet-gcdump if your applications running on runtime versions 3.1 or later and you have a Windows machine available to run PerfView or Visual Studio. Under Linux, you must use dotnet-dump for all other variants. In Windows environments, you always have the possibility to use PerfView or Visual Studio or WinDbg.

One more thing to notice: dotnet-dump generates much bigger dumpfiles compared to dotnet-gcdump. The example program shown above created the following file sizes of the respective memory images under Windows 10 and Fedora 31.

Diagnostic tool Windows 10 Fedora 31
dotnet-dump 4’116’867 KB 4’265’676 KB
dotnet-gcdump 32’708 KB 35’649 KB