BENCHMARKS · ALLOCATION & BUFFERS

new vs ArrayPool vs stackalloc — the GC pressure trade. Suite and raw reports: github.com/gdhami-net/dotnet-benchmarks.

Intel Core Ultra 9 285HX · Windows 11 · BenchmarkDotNet 0.15.8 · SDK 10.0.201 · 2026-08-22 · single run — not yet median-of-N · bars/tables: mean time, lower is better

ScratchBuffers

A 4 KB scratch buffer, 1,000 times: new array vs ArrayPool vs stackalloc.

TAKEAWAY Temporary buffers in hot paths: stackalloc for small fixed sizes, ArrayPool for anything bigger or variable. A fresh new byte[] per call is a GC tax with no upside.
In this run: ArrayPool_rent is fastest — 118.9× faster than the baseline.
RESULTS
methodnet9.0net10.0ratioallocatedΔ net10.0
New_array baseline240.9 µs ±2.0 µs263.6 µs ±38.5 µs1.00×3.93 MB+9%
ArrayPool_rent2.2 µs ±1 ns2.2 µs ±13 ns0.01×-0%
Stackalloc_span19.3 µs ±48 ns19.8 µs ±568 ns0.08×+2%
RATIO VS BASELINE · net10.0
New_array
1.00×
ArrayPool_rent
0.01×
Stackalloc_span
0.08×
THE LEDGER · SAME WORKLOAD ACROSS RELEASES (LOG)
New_arrayArrayPool_rentStackalloc_span
436.4 µs27.7 µs1.8 µs10.0.201 · 08-22 v210.0.201 · 08-22 v3
THE CODE BEING MEASURED
New_array — what this measures

new byte[4096] every time — simple, and 4 MB of garbage per thousand calls.

[Benchmark (Baseline)]
public int New_array()
{
    var sum = 0;
    for (var i = 0; i < 1_000; i++)
    {
        var buf = new byte[4096];
        buf[0] = (byte)i;
        sum += buf[0];
    }
    return sum;
}
ArrayPool_rent — what this measures

ArrayPool rent/return — reuse instead of garbage.

[Benchmark]
public int ArrayPool_rent()
{
    var pool = ArrayPool<byte>.Shared;
    var sum = 0;
    for (var i = 0; i < 1_000; i++)
    {
        var buf = pool.Rent(4096);
        buf[0] = (byte)i;
        sum += buf[0];
        pool.Return(buf);
    }
    return sum;
}
Stackalloc_span — what this measures

stackalloc inside a helper method — the frame (and the buffer) is reclaimed on every return. Never stackalloc directly in a loop: the stack only unwinds at method exit.

[Benchmark]
public int Stackalloc_span()
{
    var sum = 0;
    for (var i = 0; i < 1_000; i++) sum += UseScratch(i);
    return sum;
}

speed vs allocation

Fast is one axis. What it costs the GC is the other.

New_arrayArrayPool_rentStackalloc_span
mean time → (log)allocated → (log)New_arrayArrayPool_rentStackalloc_span