Memory in C# Under the Microscope: How the Garbage Collector Works and Why It Matters

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Magic You Must Understand

\n\n

Anyone who has written in C# for at least a couple of weeks knows: memory is managed by the runtime environment (CLR). You simply create objects using new, and when they are no longer needed, the Garbage Collector (GC) comes and cleans everything up. Sounds like magic, right? But behind this magic lies strict engineering, and if you don't understand it, your application will start to "lag," "eat" gigabytes of RAM, or even crash with an OutOfMemoryException.

\n\n

In this article, we will look under the hood of the CLR and understand exactly how memory management in C# works. You will learn how the stack differs from the heap, what object generations are, why IDisposable is your best friend, and how to avoid pitfalls with the Large Object Heap. Let's go!

\n\n

Stack and Heap: The Foundation They Don't Talk About in Textbooks

\n\n

When your program runs, the CLR divides memory into two main areas: the Stack and the Heap. Understanding the difference between them is the foundation without which everything else loses meaning.

\n\n

Stack — Fast but Small

\n

The stack is a memory area where value types (int, bool, struct, enum) and references to objects are stored. It operates on the LIFO (Last In, First Out) principle. When you call a method, a frame is allocated for it on the stack. As soon as the method completes, the frame is destroyed instantly. No garbage collector is needed here. Access speed to the stack is maximum, but its size is limited (usually 1-4 MB per thread).

\n\n
void Example()\n{\n    int x = 42;          // x is on the stack\n    string s = "Hello";  // reference s is on the stack, the object itself is on the heap\n}\n
\n\n

Heap — Slower but More Spacious

\n

The heap (Managed Heap) is the "long-term" memory. All reference types (classes, strings, arrays, delegates) live here. Memory allocation on the heap occurs with every new. And this is where the garbage collector comes into play. It decides when memory can be freed and when to wait.

\n\n

Important: The stack is not "bad," and the heap is not "good." Each has its own purpose. Value types are fast, but they cannot be passed by reference without the ref keyword. Reference types are flexible but require the GC.

\n\n

How the Garbage Collector Works in C#: Generations and Algorithm

\n\n

The garbage collector in .NET is not just "delete and forget." It is an intelligent mechanism that uses Generations to minimize pauses in application operation.

\n\n

Three Generations of Objects

\n
    \n
  • Gen 0 — newborn objects. They don't live long. Gen 0 collection happens frequently and very quickly.
  • \n
  • Gen 1 — "survivors" after one collection. A buffer zone between young and old objects.
  • \n
  • Gen 2 — long-lived objects. Gen 2 collection is the most expensive and rarest. If an object survives to Gen 2, it will likely stay there for a long time.
  • \n
\n\n

The GC algorithm, simplified, looks like this:

\n
    \n
  1. The application requests memory. If there is no space on the heap, a collection is triggered.
  2. \n
  3. The GC builds a graph of object reachability, starting from roots (global static fields, local variables on thread stacks, CPU registers).
  4. \n
  5. All unreachable objects are marked as "garbage."
  6. \n
  7. Compaction occurs — live objects are moved to prevent fragmentation.
  8. \n
  9. The freed memory is returned to the pool.
  10. \n
\n\n

Here is a clear example of how the GC affects performance:

\n\n
class HeavyObject\n{\n    public byte[] Data = new byte[1024 * 1024]; // 1 MB\n}\n\nvoid TestGC()\n{\n    for (int i = 0; i < 1000; i++)\n    {\n        var obj = new HeavyObject(); // Allocating 1 MB on the heap each time\n        // obj goes out of scope — becomes garbage\n    }\n    // After the loop, the GC may collect Gen 0 not                

Blogs

Book Recommendations