Learn .NET  

🧠 What happen Behind .NET GC (Generational Collection)?

πŸš€ 1. Memory Model in CLR

When your .NET app runs, the CLR manages memory in a space called the Managed Heap.
This heap is divided into three main generations plus the Large Object Heap (LOH):

GenerationPurposeTypical Object Lifetime
Gen 0For new, short-lived objectsTemporary/local variables
Gen 1Acts as a bufferMedium-lived objects
Gen 2For long-lived objectsGlobal/singleton objects
LOHFor large objects (>85 KB)Usually Gen 2 behavior

βš™οΈ 2. The Core Algorithm – Generational GC Concept

The core principle is:

"Most objects die young."

So .NET uses a generational approach to optimize performance:

  • Collects Gen 0 frequently

  • Collects Gen 1 occasionally

  • Collects Gen 2 rarely

This reduces pause times and CPU cost.

πŸ”¬ 3. The Step-by-Step Algorithm

Let’s go behind the scenes of what actually happens in CLR.

🧩 Step 1: Object Allocation

  • Every time you create an object (new keyword), it is allocated sequentially in the Gen 0 segment.

  • Allocation is extremely fast β€” just pointer bumping.

var user = new User(); // Allocated in Gen 0

If Gen 0 segment is full β†’ GC starts.

🧹 Step 2: GC Triggered for Gen 0

When Gen 0 is full, the GC runs:

  1. Stop the world: Application threads pause.

  2. Mark phase: GC marks all objects still reachable (rooted via stack, static variables, CPU registers).

  3. Sweep phase: Unreachable objects are removed.

  4. Compact phase: Survivors are moved down in memory to remove fragmentation.

Objects that survive are promoted to the next generation (Gen 1).

πŸ“¦ Step 3: Object Promotion

After a GC run:

Current GenerationNext Step
Survived Gen 0Move to Gen 1
Survived Gen 1Move to Gen 2
Survived Gen 2Stay in Gen 2 (until full GC)

πŸ‘‰ Promotion is the β€œaging process” of an object.

Each time an object survives a collection, its generation count increases by 1 β€” up to a max of Gen 2.

βš™οΈ Step 4: Full GC (Gen 2 Collection)

A full GC is triggered when:

  • Memory pressure is high.

  • Gen 2 (or LOH) is full.

  • The app explicitly calls GC.Collect().

Then:

  • GC scans all generations (0, 1, 2).

  • Frees memory for unreachable objects.

  • May compact the heap (in Compacting GC mode).

This is expensive β€” can cause noticeable application pause.

🧬 5. Internal Algorithm (Simplified Pseudocode)

Here’s a simplified model of how the CLR GC decides what to collect:

while (applicationRunning)
{
    allocateObject();

    if (Gen0.isFull)
        CollectGeneration(0);

    if (Gen1.isFull)
        CollectGeneration(1);

    if (Gen2.isFull || systemMemoryLow)
        CollectGeneration(2);
}

void CollectGeneration(int gen)
{
    MarkLiveObjects(gen);
    SweepDeadObjects(gen);
    CompactHeap(gen);
    PromoteSurvivors(gen);
}

Promotion Logic

void PromoteSurvivors(int gen)
{
    foreach (var obj in survivors)
    {
        obj.Generation = Math.Min(obj.Generation + 1, 2);
    }
}

🧩 6. Example: Object Lifetime in Action

void Example()
{
    // Gen 0 allocation
    var temp = new StringBuilder("short-lived");
    
    // Another allocation
    var user = new UserProfile(); // long-lived
}
EventWhat Happens
Objects createdBoth go into Gen 0
Temp no longer usedCollected in next Gen 0 GC
UserProfile still usedPromoted to Gen 1
Survives more GCsPromoted to Gen 2

After a while:

  • temp is gone.

  • user sits in Gen 2, living a long life.

🧠 7. GC Modes and Optimizations (Latest .NET)

In .NET 8 / .NET 9, the GC is smarter:

GC ModeDescription
Workstation GCOptimized for low-latency desktop apps
Server GCMulti-threaded, high-throughput mode
Background GCRuns concurrently without blocking threads
SustainedLowLatency GCUsed for gaming, trading, or real-time apps (prevents full GC)

You can control this via AppContext or runtimeconfig.json.

⚑ 8. Compacting Algorithm (Memory Defragmentation)

When GC compacts:

  • Surviving objects are moved to fill holes left by collected ones.

  • References are updated automatically.

  • This improves memory locality and cache efficiency.

πŸ‘‰ This is why you never use raw pointers to managed objects β€” GC can move them anytime.

🧩 9. Large Object Heap (LOH) Behavior

  • Objects > 85 KB go into the LOH.

  • LOH is part of Gen 2.

  • Until .NET 4.5, it was not compacted.

  • From .NET 8, LOH compaction is optional (via GCSettings.LargeObjectHeapCompactionMode).

πŸ” 10. Visual Flow Summary

[Object created] β†’ Gen 0
     ↓ (survives GC)
β†’ Gen 1
     ↓ (survives more GCs)
β†’ Gen 2
     ↓
β†’ (collected in full GC)

🧾 11. Performance Tip Summary

TipDescription
Minimize object creationKeeps Gen 0 small and fast
Reuse objects / poolingAvoid constant promotion
Use using and Dispose()Helps release unmanaged resources
Avoid GC.Collect()Let GC manage timing
Use profiling tools(dotMemory, PerfView, Visual Studio Diagnostics)

πŸ’¬ 12. Interview Q&A

❓Q1. What is the logic behind object promotion in .NET GC?

Answer:
When an object survives a collection in its current generation, it’s promoted to the next generation (Gen 0 β†’ Gen 1 β†’ Gen 2).
Objects that survive multiple collections are assumed to be long-lived.

❓Q2. Why does .NET use generations?

Answer:
Because most objects die young. By collecting only young generations frequently, GC reduces pause times and CPU usage.

❓Q3. When does a full GC occur?

Answer:
When Gen 2 or LOH is full, or when system memory pressure is high, or when the developer calls GC.Collect() manually.

❓Q4. What happens during compaction?

Answer:
GC moves surviving objects together to remove fragmentation and updates all references automatically.

❓Q5. Can the GC move objects in memory?

Answer:
Yes, except for objects in the pinned state (like fixed buffers or stackalloc memory).
This movement is why references are managed.

❓Q6. What’s new in .NET 8 GC?

Answer:

  • Enhanced background GC

  • Optional LOH compaction

  • Better adaptive heuristics

  • Support for sustained low-latency modes

❓Q7. What triggers Gen 0 vs Gen 2 collection?

TriggerGeneration
Gen 0 fullMinor GC
Gen 1 fullMedium GC
Gen 2 full or memory lowFull GC

🏁 Final Thoughts

  • Gen 0: For short-lived objects β†’ collected frequently

  • Gen 1: For medium-lived β†’ collected occasionally

  • Gen 2: For long-lived β†’ collected rarely

The CLR GC algorithm is a mark-sweep-compact generational collector β€” highly optimized for real-world workloads.

In .NET 8+, it’s so smart that manual memory management is almost never required β€” just follow clean object lifetime practices, and GC will handle the rest.