WMemoryProfiler is (to my knowledge) the the first free profiler that you can use inside integration tests to verify that your component does not leak memory.

With version 2 it uses not Windbg for heap memory snapshots but ClrMD wich allows you to take consistent heap snapshots at safe timepoints.

 
using (ProcessMemoryDumper dumper = new ProcessMemoryDumper(p.Id))
{
    var stats = dumper.GetMemoryStatistics();
    var top10 = stats.ManagedHeapStats
                        .OrderByDescending(x => x.Value.InstanceCount)
                        .Take(10)
                        .ToArray();

    Console.WriteLine("{0:N0} allocated objects with {1:N0} bytes allocated on the managed heap", stats.TotalInstanceCount, stats.TotalAllocatedMangedHeapBytes);
    foreach (var kvp in top10)
    {
        Console.WriteLine("Type {0} has {1} instances", kvp.Key, kvp.Value.InstanceCount);
    }
}

62.747 allocated objects with 6.168.072 bytes allocated on the managed heap
Type System.String has 13670 instances
Type System.Reflection.RuntimeMethodInfo has 1943 instances
Type System.RuntimeType has 1651 instances
Type System.Object has 1527 instances
Type Microsoft.PowerShell.Commands.Internal.Format.ExpressionToken has 1380 instances
Type System.Int32 has 1341 instances
Type System.Management.Automation.Language.InternalScriptExtent has 1328 instances
Type Microsoft.PowerShell.Commands.Internal.Format.FormatToken[] has 1118 instances
Type System.Collections.Generic.List<Microsoft.PowerShell.Commands.Internal.Format.FormatToken> has 1117 instances
Type System.String[] has 915 instances

 

It also supports more sophisticated asserts based on object count or total memory per type or total heap size.

image

 

// Attach to process
using (ProcessMemoryDumper dumper = new ProcessMemoryDumper(p.Id))
{
    // get current managed heap
    var first = dumper.GetMemoryStatistics();

    // simulate leak 
    first.ManagedHeapStats["System.String"].InstanceCount -= 5000;

    // get second heapsnapshot and get diff
    var diff = dumper.GetMemoryStatisticsDiff(first);

    // Create assserter which asserts when more than 4999 instances were added
    DiffAssert asserter = new DiffAssert(new DiffThreshold
    {
        MaxAddedInstances = 4999,
        Type = "System.String"
    },
    (string type, DiffThreshold violated) => Assert.Fail(type));

    // assert when the diff is violated
    asserter.Assert(diff);
}

The only thing you need to remember is to start your application not under the debugger since this API does need to make use of Windbg under the hood to make this output happen. An interesting side note might be that what you have seen is a process that did start a debugger, attach it to itself and did control the debugger. Self debugging at its best. This functionality is also exposed via the CdbEng (pure Windbg) and MdbEng (managed debugger).

 

For a full feature list see the Documentation Tab.

Last edited Jan 8 at 12:12 PM by Alois, version 8