Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
To find a .NET memory leak, first confirm that memory remains elevated under a repeatable workload, then compare heap evidence to identify growing object types and inspect their root paths to learn what keeps them alive. Fix the owning code path and repeat the same workload to verify that the growth has stopped.
What counts as a memory leak in .NET?
A managed memory leak is usually unwanted object retention: an object the application no longer needs remains reachable through live references, so the garbage collector cannot reclaim it. Microsoft describes this as an app referencing objects it no longer needs to perform its task (Microsoft Learn: Debug a memory leak in .NET). Continued retention can degrade performance and, in severe cases, contribute to an OutOfMemoryException.
High allocation during a busy workload is not, by itself, proof of a leak. Allocations may be short-lived and later collected. The useful distinction is whether memory returns toward its prior level after the workload subsides, or whether retained memory continues to accumulate.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →How can you tell whether memory keeps growing?
Use a repeatable workload that exercises the suspected feature, and watch runtime counters before collecting a dump. Microsoft’s diagnostic walkthrough begins by confirming growth with dotnet-counters; counter names and presentation can vary by runtime version, so consult the current tool guidance for your environment.
#1 Best Overall
dotnet-counters ps
dotnet-counters monitor --refresh-interval 1 -p <process-id>
The first command lists .NET processes; the second monitors the selected process, refreshing once per second. The process identifier is the PID reported for the target. The Microsoft walkthrough lists .NET Core 3.1 SDK or later for its sample, and notes that the user interface differs for applications running versions earlier than .NET 9.
- Run the same workload for a consistent duration and record memory behavior while it runs and afterward.
- Distinguish a temporary rise from memory that remains elevated or continues trending upward across repeated runs.
- If growth is persistent, capture evidence at comparable points in time so you can compare what changed.
Which .NET memory diagnostic tool should you use?
| Situation | Starting point | Important trade-off |
|---|---|---|
| Confirm growth while the app runs | dotnet-counters |
Use it to observe behavior before collecting heavier diagnostic data. |
| Inspect heap contents and retaining references | dotnet-dump with SOS |
Detailed analysis is possible, but dump collection can add substantial memory pressure. |
| Inspect live GC heap data and compare object counts or roots | dotnet-gcdump |
Large heaps can produce incomplete data; collection and buffering consume memory. |
| Profile on Windows in a GUI | Visual Studio Memory Usage snapshots; .NET Object Allocation tool for allocation paths | Profiling can slow the application; allocation data complements rather than replaces retained-object analysis. |
The command-line diagnostic workflow does not require Visual Studio. Choose based on whether you need to observe growth, inspect retained heap objects, trace allocations, or work in a Windows profiling interface.
Rank #2
How do you capture comparable heap evidence?
Collect a process dump with dotnet-dump
Install the global tool, collect a dump from the target process, and open it in the SOS analysis prompt:
Recommended Free Tools
dotnet tool install --global dotnet-dump
dotnet-dump collect -p <process-id>
dotnet-dump analyze <dump-path>
For a comparison, leave the application running and collect another dump after a similar workload or interval. Differences between captures can reveal which object types are accumulating. Follow Microsoft’s current dotnet-dump documentation for platform and runtime-specific details.
Rank #3
- Run collection as the target process user or as root.
- On Linux or macOS, ensure the target and diagnostic tool use the same
TMPDIR. - In containers, collection may require
SYS_PTRACEand an appropriate security profile. - Full or heap dumps can page in substantial virtual memory. In a memory-limited container, the additional pressure can exceed the limit and get the container terminated.
Dumps can contain sensitive process data. Store, transfer, and grant access to them as carefully as you would other potentially sensitive application data; see Microsoft’s guidance on dumps.
Use dotnet-gcdump for live GC heap data when appropriate
dotnet-gcdump gathers GC heap data from a live process through EventPipe and can help compare object counts and inspect roots. Collection induces a generation 2 GC. For sufficiently large heaps, event data may be dropped and the resulting heap graph may be incomplete; Microsoft recommends collecting a process dump in that case. The target’s event buffer can grow up to 256 MB, and the tool also consumes memory, so account for both in constrained environments. Details and troubleshooting guidance are in Microsoft’s dotnet-gcdump documentation.
Rank #4
How do you find what is holding an object in memory?
Find types that occupy or accumulate heap space
At the SOS prompt opened by dotnet-dump analyze, start with heap statistics:
dumpheap -stat
dumpheap -type MyCompany.Component -stat
dumpheap -stat reports object counts and total size grouped by type. The optional type filter narrows a broad report to a namespace or type of interest. Compare reports from separate captures when available. A large type is a useful lead, not proof of a leak: it may be expected for the workload.
Trace roots for the suspect objects
Use SOS gcroot on suspect objects to inspect the live reference chains that make them reachable. The key is to identify the owner that still points to objects the application no longer needs. Microsoft’s example traces a Customer through a CustomerCache and list or array objects, illustrating how retained cache contents can keep customers alive.
Follow the root path back to application ownership and examine that owner’s lifetime, eviction, and cleanup behavior. Do not assume that calling Dispose fixes every managed leak: disposal is relevant to disposable resources, but it does not automatically remove arbitrary managed references. The right fix depends on the retaining path shown by the evidence.
How can Windows developers compare memory snapshots?
Use Visual Studio Memory Usage
In Visual Studio, open Debug > Performance Profiler, select Memory Usage, start the scenario, and take snapshots at comparable points. Compare snapshots to see changes in object counts and bytes, inspect managed types, and follow paths to roots. Microsoft recommends this Performance Profiler workflow for release builds in its memory-usage guidance.
Free tools Windows power users keep installed
One-click scans. No signup required.
Use allocation profiling to find creation paths
The .NET Object Allocation tool reports execution paths that create objects, helping identify allocation-heavy code. It answers a different question from retained-object analysis: a hot allocation path shows where objects are created, while heap snapshots and roots help determine why objects remain alive. Collection can slow the profiled application. If you do not need every allocation tracked, adjusting the sampling rate can reduce the profiling cost. See Microsoft’s guidance for analyzing .NET object memory usage with the Object Allocation tool.
How do you verify the fix?
- Change the code at the ownership path identified by the heap roots—for example, correct the actual owner’s lifetime or cleanup/eviction behavior.
- Restart or reset the application state as appropriate, then run the same workload for a comparable duration.
- Check counters for persistent growth and collect new snapshots or dumps at matching points.
- Compare object counts, sizes, and root paths with the earlier evidence. Confirm that the unwanted objects no longer accumulate or remain retained through the problematic path.
A fix is supported when the same scenario no longer reproduces the retained-object growth. If memory still rises, inspect the new comparison rather than assuming the first change addressed every retaining path.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

