Forcing Garbage Collection
2 min readForcing Garbage Collection
TL;DR
GC.Collect() and friends force a full, blocking collection across all generations — useful in benchmark setup or memory-snapshot tooling, but almost never in production hot paths, where they spike latency and defeat the GC's own heuristics. The senior answer to "memory feels bloated" is to reduce allocation rate, pool buffers, and fix leaks; reach for GC.TryStartNoGCRegion for short critical windows and one-shot LOH compaction only during maintenance.
How it works
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, blocking: true, compacting: true);
GC.WaitForPendingFinalizers();
GC.Collect();
- Forces collection of all generations and waits for finalizers. Use only for diagnostic tools or when transitioning between phases (e.g., benchmark setup vs measurement).
- In production code, let the GC run heuristically—manual collection can hurt throughput and latency.
Quick recall Q&A
GC.Collect()?During benchmarking (to start from a clean slate) or tooling scenarios (e.g., before capturing a memory snapshot). Avoid in normal application flow.
It pauses all managed threads, potentially causing latency spikes and throughput loss, negating the GC’s heuristics.
Set GCSettings.LargeObjectHeapCompactionMode = CompactOnce, call GC.Collect() with compacting enabled, typically during maintenance windows.
GC.WaitForPendingFinalizers() between collections?To ensure finalizers from the first collection run before initiating another GC pass, guaranteeing cleanup of finalizable objects.
Force GC during setup/cleanup phases, not inside the measured benchmark method, so the measurement represents steady-state behavior.
GC.Collect() free native resources?Only indirectly—finalizers may release native handles. For deterministic cleanup, implement IDisposable instead of relying on GC.
GC.Collect() in production?Use ETW/EventPipe or dotnet-trace to capture GC start reasons. Forced GCs show up with reason Induced.
Reduce allocation rates, pool objects, and fix leaks rather than forcing collections. Use GC.TryStartNoGCRegion for temporary low-latency windows instead.
Calling GC.Collect() invalidates NoGCRegion. Instead, exit the region properly or avoid entering it if you plan to induce GC.
Yes via GC.Collect(0), but even that incurs overhead. Rely on GC heuristics unless you have a proven diagnostic need.