Course contentsShow
← C#
Lesson 1738 of 1,90816. Performance and DiagnosticsFree lesson

Profiling Memory Footprint with DotMemory

Students will utilize snapshot comparison techniques to find exact memory growth sources.

Profiling Memory Footprint with DotMemory

In this lesson, you will learn how to isolate specific memory growth issues by comparing two snapshots of your application’s heap state in dotMemory.

When you suspect a memory leak or an unintended increase in your application's memory footprint, looking at a single point in time is rarely enough. The real insights come from "Snapshot Comparison." By taking a baseline snapshot, performing a specific set of operations, and then taking a second snapshot, you can mathematically isolate exactly which objects were created and—crucially—which ones failed to be collected.

The Comparison Workflow

To find the source of growth, use the following workflow within dotMemory:

  1. Snapshot 1 (Baseline): Capture the state of your application after it has reached a "steady state" (e.g., after the initial warm-up).
  2. Perform Action: Execute the logic you suspect is causing the growth (e.g., repeatedly calling a method that processes domain aggregates).
  3. Snapshot 2: Capture the state immediately after the action, then trigger a manual Garbage Collection (GC) in the profiler to clear out short-lived, transient objects.

Analyzing the "Diff"

Once you have your two snapshots, compare them using the "Diff" view. You are specifically looking for the "Survivor" count. If you perform a loop of 100 iterations and the "Diff" shows 100 new instances of a specific OrderProcessor or DataContainer that were not present in the baseline, you have found a leak.

// Example: A common culprit causing a memory growth spike
public void ProcessItems(List<Item> items) 
{
    foreach (var item in items) 
    {
        // If 'EventHandler' is registered here but never unsubscribed, 
        // the object will show as a "Survivor" in the diff analysis.
        _eventAggregator.Subscribe(item); 
    }
}

By filtering for objects that are "New" and survived the GC, you move from guessing why memory is increasing to seeing the exact type responsible for the bloat. Focus your investigation on the "Back References" or "Paths to Root" for those specific objects; this will point you directly to the static collection or event subscription holding them in memory.

Key Takeaway: Comparing two memory snapshots after forcing a Garbage Collection allows you to isolate persistent memory growth by highlighting objects that were allocated but never reclaimed.