Making .NET Garbage Collector Take a Break

Elijah Koulaxis

February 6, 2026

Photo generated by Gemini dotnet-garbage-collector.png

So you want your C# code to run fast, like, really fast, for a brief moment? Maybe you're processing real-time audio, handling network packets, or doing some time-sensitive game logic where even a tiny pause is unacceptable.

This is where GC.TryStartNoGCRegion() could come in handy for you :D

What Are We Trying To Solve?

Normally, .NET's GC runs whenever it feels like cleaning up unused memory. Most of the time, this is awesome right, you don't have to manually manage memory and everything just works. Not quite though. Sometimes, GC picks the worst possible moment to pause your program and do its cleanup work

Imagine you're in the middle of processing a chunk of audio data that needs to go out to the speakers right now, and suddenly the GC decides to stop everything for 5-10 ms to collect garbage. Your audio stutters and your users are sad...

How Can You Achieve That?

Setting up your budget

First of all, you want to set up your memory budget:

const long bBytes = 2 * 1024 * 1024 // 2MB in this case

You're telling the runtime: "Hey, I'm about to do some work, and I promise I won't allocate more than 2MB of new memory" This is your budget. Stay under it, and the GC won't interrupt you

Entering the No-GC Zone

if (!GC.TryStartNoGCRegion(bBytes))
{
    Console.WriteLine("Could not start...");
    return;
}

This is where you actually ask the runtime to disable garbage collection. The Try part is important because this can fail if there's not enough free memory available, or a GC is already running, or generally speaking the runtime can't just guarantee it.

Just remember that if it returns false, bail out gracefully. Don't force it

Do Your Important Work

byte[] data = new byte[1024]; 
Span<byte> buffer = data;

try
{
    for (int i = 0; i < 100_000; i++)
    {
        DoWork(ref buffer);
    }
}

Now everything's running while GC is taking a break :D

Very important note: We're using a Span<byte> here. This is super important because Span is a stack-allocated type that doesn't create heap allocations. If you were creating new objects, strings, or arrays, in this loop, you'd blow your budget real quick and the GC would wake up anyway

Always Clean Up

You definitely need a finally block to make sure that no matter what happens, you tell the GC it can wake up and resume normal operations

If for any case you exceeded your budget during the no-GC region, the runtime might have already been forced to trigger a collection. In that case, EndNoGCRegion() will throw an InvalidOperationException to let you know you broke your promise

finally
{
    try
    {
        GC.EndNoGCRegion();
    }
    catch (InvalidOperationException ex)
    {
        Console.WriteLine("Budget exceeded: " + ex.Message);
    }
}

What's Happening Under the Hood?

There are certain things that happen under the hood for everything to work out as expected. Here's the gist:

  1. ◆ The runtime examines the current heap state and verifies there's enough free memory to satisfy your budget without needing a collection
  2. ◆ It essentially locks a chunk of memory for your use, to make sure that even if you allocate up to your budget, there won't be a need to collect garbage
  3. ◆ The normal behaviors that trigger GC are obviously disabled, such as "we've allocated X bytes since last GC" or "we're running low on memory"
  4. ◆ You do your thing and the GC won't interrupt you, but you must stay within your budget
  5. Don't forget to re-enable GC

When Should You Use It?

Finally, this will help you understand when could you even use this, perhaps, new knowledge you've just gained.

Some good cases would be real-time audio/video processing, trading, game engine critical paths, network processing, parsing etc

Some bad cases would be long-running applications, when you're allocating a lot of objects, normal application code(premature optimization is the root of all evil), I/O bound operations because obviously GC pauses aren't your bottleneck

Tags:
Back to Home