Garbage Collection and Memory in .NET
Codevity Admin · 10/25/2026
Codevity Admin · 10/25/2026
You do not free memory by hand in C#. The garbage collector (GC) does it. Interviewers want to see that you understand roughly how, what it does not clean up, and how programs still leak memory.
| Stack | Managed heap | |
|---|---|---|
| Holds | Local value-type variables, method arguments, references | Objects of reference types, and anything inside them |
| Allocation | Very fast: move a pointer | Allocated by the runtime, reclaimed by the GC |
| Lifetime | Ends when the method returns | Until no references reach the object |
| Cleanup | Automatic and immediate | Garbage collector, at times it chooses |
See value and reference types for the detail on where value types actually live.
The GC finds objects that the program can no longer reach, starting from the roots (local variables, static fields, CPU registers), and reclaims their memory. It then compacts the surviving objects together.
It is generational, based on the observation that most objects die young:
| Generation | Contains | Collected |
|---|---|---|
| Gen 0 | Newly allocated, short-lived objects | Very often, and very quickly |
| Gen 1 | Survivors of a Gen 0 collection | Less often. A buffer between short and long-lived |
| Gen 2 | Long-lived objects (caches, static data) | Rarely. A full collection is the most expensive |
An object that survives a collection is promoted to the next generation. Objects of 85,000 bytes or more go to the large object heap, which is collected together with Gen 2 and is not compacted by default, so allocating many big arrays can hurt.
var item = new object();
Console.WriteLine(GC.GetGeneration(item)); // 0 (just allocated)
GC.Collect(); // for demonstration only
Console.WriteLine(GC.GetGeneration(item)); // 1 (it survived, so it was promoted)Do not call GC.Collect() in real code. The collector knows better than you when to run, and forcing it usually makes performance worse.
The GC reclaims memory. It does not close files, database connections or sockets in a timely way: those need Dispose(), usually through . See exceptions and IDisposable.
A finalizer () is a last-chance method the GC calls before reclaiming an object. They are slow and unpredictable:
So: implement for deterministic cleanup, and add a finalizer only as a safety net for unmanaged resources, calling in .
"Memory leak" in C# means an object stays reachable when you no longer need it, so the GC cannot free it. The usual causes:
To find a leak, take memory snapshots in Visual Studio or use and , then look at what holds a reference to the objects that keep growing.
using~ClassName()IDisposableGC.SuppressFinalize(this)Dispose()List<T>Dictionary<K, V>HttpClientdotnet-countersdotnet-gcdumpusingDispose()GC.Collect()int[100_000]WeakReference