The NativeMemoryProfiler
uses EtwProfiler
to profile the code using ETW and adds the extra columns Allocated native memory
and Native memory leak
to the benchmark results table.
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Diagnostics.Windows.Configs;
using BenchmarkDotNet.Filters;
namespace BenchmarkDotNet.Samples
{
[ShortRunJob]
[NativeMemoryProfiler]
[MemoryDiagnoser]
public class IntroNativeMemory
{
#pragma warning disable CA1416
[Benchmark, WindowsOnly]
public void BitmapWithLeaks()
{
var flag = new Bitmap(200, 100);
var graphics = Graphics.FromImage(flag);
var blackPen = new Pen(Color.Black, 3);
graphics.DrawLine(blackPen, 100, 100, 500, 100);
}
[Benchmark, WindowsOnly]
public void Bitmap()
{
using (var flag = new Bitmap(200, 100))
{
using (var graphics = Graphics.FromImage(flag))
{
using (var blackPen = new Pen(Color.Black, 3))
{
graphics.DrawLine(blackPen, 100, 100, 500, 100);
}
}
}
}
#pragma warning restore CA1416
private const int Size = 20; // Greater value could cause System.OutOfMemoryException for test with memory leaks.
private int ArraySize = Size * Marshal.SizeOf(typeof(int));
[Benchmark]
public unsafe void AllocHGlobal()
{
IntPtr unmanagedHandle = Marshal.AllocHGlobal(ArraySize);
Span<byte> unmanaged = new Span<byte>(unmanagedHandle.ToPointer(), ArraySize);
Marshal.FreeHGlobal(unmanagedHandle);
}
[Benchmark]
public unsafe void AllocHGlobalWithLeaks()
{
IntPtr unmanagedHandle = Marshal.AllocHGlobal(ArraySize);
Span<byte> unmanaged = new Span<byte>(unmanagedHandle.ToPointer(), ArraySize);
}
private class WindowsOnlyAttribute : FilterConfigBaseAttribute
{
public WindowsOnlyAttribute()
: base(new SimpleFilter(_ => RuntimeInformation.IsOSPlatform(OSPlatform.Windows)))
{
}
}
}
}
Output Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated Allocated native memory Native memory leak BitmapWithLeaks 73,456.43 ns 22,498.10 ns 1,233.197 ns - - - 177 B 13183 B 11615 B Bitmap 91,590.08 ns 101,468.12 ns 5,561.810 ns - - - 180 B 12624 B - AllocHGlobal 79.91 ns 43.93 ns 2.408 ns - - - - 80 B - AllocHGlobalWithLeaks 103.50 ns 153.21 ns 8.398 ns - - - - 80 B 80 B Profiling memory leaks
The BenchmarkDotNet repeats benchmarking function many times. Sometimes it can cause a memory overflow. In this case, the BenchmarkDotNet shows the message:
OutOfMemoryException!
BenchmarkDotNet continues to run additional iterations until desired accuracy level is achieved. It's possible only if the benchmark method doesn't have any side-effects.
If your benchmark allocates memory and keeps it alive, you are creating a memory leak.
You should redesign your benchmark and remove the side-effects. You can use `OperationsPerInvoke`, `IterationSetup` and `IterationCleanup` to do that.
In this case, you should try to reduce the number of invocation, by adding [ShortRunJob]
attribute or using Job.Short
for custom configuration.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4