Sizoscope is a binary size investigation tool to help you optimize and reduce the size of your .NET Native AOT binaries.
It supports visualizing the size contributions of individual methods and types, but also namespaces and assemblies. It also allows diffing before/after snapshots and offers basic root cause analysis.
$ dotnet tool install sizoscope --global
For command-line diffing (no GUI), install the CLI tool:
$ dotnet tool install sizoscope-cli --global
Alternatively, download a release from the Releases tab. The releases on the Releases tab are built with native AOT and are fully standalone/portable ZIPs. They work great under Linux with Wine.
There's an Avalonia-based fork of Sizoscope maintained by @hez2010 here.
The tool only supports the Native AOT deployment model in .NET 7 or later. After enabling Native AOT deployment on your project as documented in the linked doc (basically, add <PublishAot>true</PublishAot> to a PropertyGroup in your project), add following lines to the project to enable generation of additional compile-time diagnostic files:
<PropertyGroup>
<IlcGenerateMstatFile>true</IlcGenerateMstatFile>
<IlcGenerateDgmlFile>true</IlcGenerateDgmlFile>
</PropertyGroup>
Once you have that, dotnet publish your project as usual. After publishing, you should see a *.mstat and *.dgml.xml file under obj\Release\net[7|8].0\[linux|win]-[x64|arm64]\native - these are the files Sizoscope operates on.
Launch the tool and open the MSTAT file. The associated *.dgml.xml file will be loaded automatically if it's next to the *.mstat. If the *.dgml.xml doesn't exist, root cause analysis will not work.
Once the file loads, you'll be greeted with the main screen that shows assembly contributions:

You can click around things that look interesting. You can also open the search subwindow where you can sort individual entries by exclusive/inclusive size.
If you have a different MSTAT file you'd like to compare with, click the Diff button to enter a diff view:

The diff view will show you things that are unique to the baseline on the left and things that are unique to the compared MSTAT on the right.
ℹ️ NOTE: Root analysis is only supported starting in .NET 8. The MSTAT files generated with older SDKs don't have the necessary information.
The main window and the diff window will show you what is in the binary, but not why it's in the binary. Double-clicking a node in the main window or diff window will open a root analysis window. This will try to explain why something was included.

In the above screenshot, the reason why the top node was included in the executable was all the things nested under it. Some nodes have two reasons. This is typical for e.g. virtual method implementations - the reason why a virtual method implementation is generated is that both the virtual method gets called somewhere and a type implementing the method was allocated. The screenshot has one such situation for SyncTextWriter.WriteLine.
.zip archives containing .mstat (and optionally .scan.dgml.xml) files. The .mstat is read directly from the archive without extracting to disk.The sizoscope-cli tool provides a non-interactive way to diff two MSTAT files:
$ sizoscope-cli baseline.mstat compare.mstat
Total accounted size difference: 206.2 kB
=== New / Grown ===
+129.0 kB System.Private.CoreLib
+52.4 kB System.Net.Http
...
=== Removed / Shrunk ===
-1.2 kB System.Collections
...
To write output to a file instead of stdout:
$ sizoscope-cli baseline.mstat compare.mstat --output diff.txt
ZIP archives work as well:
$ sizoscope-cli baseline.mstat.zip compare.mstat.zip
(top 24 of 26)
717 followers · starred Dec 2023
338 followers · starred Mar 2023
299 followers · starred Aug 2024
379 followers · starred Jun 2023
Sizoscope is a binary size investigation tool to help you optimize and reduce the size of your .NET Native AOT binaries.
It supports visualizing the size contributions of individual methods and types, but also namespaces and assemblies. It also allows diffing before/after snapshots and offers basic root cause analysis.
$ dotnet tool install sizoscope --global
For command-line diffing (no GUI), install the CLI tool:
$ dotnet tool install sizoscope-cli --global
Alternatively, download a release from the Releases tab. The releases on the Releases tab are built with native AOT and are fully standalone/portable ZIPs. They work great under Linux with Wine.
There's an Avalonia-based fork of Sizoscope maintained by @hez2010 here.
The tool only supports the Native AOT deployment model in .NET 7 or later. After enabling Native AOT deployment on your project as documented in the linked doc (basically, add <PublishAot>true</PublishAot> to a PropertyGroup in your project), add following lines to the project to enable generation of additional compile-time diagnostic files:
<PropertyGroup>
<IlcGenerateMstatFile>true</IlcGenerateMstatFile>
<IlcGenerateDgmlFile>true</IlcGenerateDgmlFile>
</PropertyGroup>
Once you have that, dotnet publish your project as usual. After publishing, you should see a *.mstat and *.dgml.xml file under obj\Release\net[7|8].0\[linux|win]-[x64|arm64]\native - these are the files Sizoscope operates on.
Launch the tool and open the MSTAT file. The associated *.dgml.xml file will be loaded automatically if it's next to the *.mstat. If the *.dgml.xml doesn't exist, root cause analysis will not work.
Once the file loads, you'll be greeted with the main screen that shows assembly contributions:

You can click around things that look interesting. You can also open the search subwindow where you can sort individual entries by exclusive/inclusive size.
If you have a different MSTAT file you'd like to compare with, click the Diff button to enter a diff view:

The diff view will show you things that are unique to the baseline on the left and things that are unique to the compared MSTAT on the right.
ℹ️ NOTE: Root analysis is only supported starting in .NET 8. The MSTAT files generated with older SDKs don't have the necessary information.
The main window and the diff window will show you what is in the binary, but not why it's in the binary. Double-clicking a node in the main window or diff window will open a root analysis window. This will try to explain why something was included.

In the above screenshot, the reason why the top node was included in the executable was all the things nested under it. Some nodes have two reasons. This is typical for e.g. virtual method implementations - the reason why a virtual method implementation is generated is that both the virtual method gets called somewhere and a type implementing the method was allocated. The screenshot has one such situation for SyncTextWriter.WriteLine.
.zip archives containing .mstat (and optionally .scan.dgml.xml) files. The .mstat is read directly from the archive without extracting to disk.The sizoscope-cli tool provides a non-interactive way to diff two MSTAT files:
$ sizoscope-cli baseline.mstat compare.mstat
Total accounted size difference: 206.2 kB
=== New / Grown ===
+129.0 kB System.Private.CoreLib
+52.4 kB System.Net.Http
...
=== Removed / Shrunk ===
-1.2 kB System.Collections
...
To write output to a file instead of stdout:
$ sizoscope-cli baseline.mstat compare.mstat --output diff.txt
ZIP archives work as well:
$ sizoscope-cli baseline.mstat.zip compare.mstat.zip
(top 24 of 26)
717 followers · starred Dec 2023
338 followers · starred Mar 2023
299 followers · starred Aug 2024
379 followers · starred Jun 2023