Garbage Collection in .NET
The problem
A managed runtime promises automatic memory management, but 'automatic' still needs an actual algorithm deciding what to reclaim and when — get that algorithm wrong or misunderstand its behavior, and a long-running server can accumulate memory it never needed to keep, or pause unpredictably while cleaning up.
Why now
JavaScript's garbage collection already established reachability as the general criterion for what gets freed; .NET's collector uses that same criterion but adds a specific, generational strategy on top of it — this topic is where the same core idea gets a second, meaningfully different concrete implementation worth comparing directly.
Mental model
.NET's garbage collector is generational: it observes that most objects die young, so it checks recently-created objects (Gen 0) far more often and cheaply than long-lived ones, promoting anything that survives a collection into an older generation checked less frequently — the same reachability test JavaScript's collector already uses, just applied more often to the objects statistically most likely to already be garbage, which is what keeps collection pauses short for typical workloads.
Requires
- Garbage CollectionJavaScript Runtime
This topic assumes the reachability-based collection criterion already established there and extends it with .NET's specific generational strategy; you need that general model in place before comparing implementations is more useful than learning from scratch.
- The CLR & Managed Execution.NET Internals
Garbage collection is one of the CLR's core managed-execution responsibilities already introduced generally; you need that framing (the CLR manages memory for you) before its specific collection algorithm is meaningful detail rather than an isolated fact.
Used in
- Every .NET application's automatic memory management, invisibly, for the vast majority of code
- Diagnosing performance issues caused by excessive Gen 0 collections from too much short-lived allocation
- Server GC versus Workstation GC configuration for throughput-sensitive backend services
- Understanding IDisposable and using blocks for deterministic cleanup of unmanaged resources the GC alone can't handle
Projects
- Write a program that deliberately allocates a large number of short-lived objects in a loop, observe frequent Gen 0 collections using a profiler, then reduce allocations and compare collection frequency
- Explain, using a diagram, how an object survives from Gen 0 to Gen 1 to Gen 2 across successive collections, and why that promotion reduces overall collection cost
Examples
- A tight loop allocating a new small object every iteration triggers frequent, cheap Gen 0 collections — usually fine, but excessive allocation churn can still show up as measurable overhead under profiling
- A cached object that lives for the entire application's lifetime gets promoted to Gen 2 and is checked only rarely, which is exactly the generational hypothesis (most objects die young, a few live long) working as intended
Resources
Mastery checklist
- I can explain the generational hypothesis and why it makes collection cheaper on average
- I can explain the difference between Gen 0, Gen 1, and Gen 2 collections
- I can use a profiler to identify excessive allocation causing frequent Gen 0 collections
- I can explain why IDisposable and using blocks exist despite automatic garbage collection