Memory and the garbage collector
In C#, locals live in a method's stack frame and every object made with new lives on the managed heap, which the CLR owns. Follow a seven-line program as it allocates two objects in generation 0, drops one reference, and forces a gen 0 collection: the garbage collector marks what the roots reach, reclaims the rest, compacts and promotes the survivor to gen 1, and updates the reference to it. GC.GetGeneration then prints 1.
5 quick questions
Pick an answer to see why. Your score saves with your progress.
01Right after line 3 (b = null;), what has happened to Order(2)'s memory?
Setting the last reference to null only makes the object unreachable. The garbage collector reclaims its memory the next time it collects that generation; here that is line 4.
02Which of these is NOT a garbage collection root?
Roots are where marking starts: locals on each thread's stack, static fields, CPU registers, GC handles and the finalization queue. An object nothing refers to is exactly what marking never reaches.
03Why does a's value change from 0xA000 to 0x8000 during the collection?
A compacting collection moves surviving objects together (here into gen 1) and, in its relocating phase, updates every reference so they point at the new place. Your code never sees a stale address.
04The program prints 1. Why?
New objects start in gen 0. Objects that survive a gen 0 collection are promoted to gen 1; survivors of a gen 1 collection move to gen 2, where they stay.
05Where does new byte[100_000] go, and when is it collected?
Objects of 85,000 bytes or more are allocated on the large object heap. It is collected only during generation 2 (full) collections, which is why short-lived large buffers are costly.
Glossary
- Managed heap
- The memory the CLR owns for objects created with new. You never free it yourself; the garbage collector does.
- Stack frame
- The memory a method gets for its locals while it runs. It disappears when the method returns.
- Reference
- A value that holds an object's address on the heap. A local such as a holds a reference, not the object itself.
- Garbage collector (GC)
- The part of the CLR that finds objects no root can reach and reclaims their memory.
- Root
- A starting point for marking: a local on a thread's stack, a static field, a CPU register, a GC handle or the finalization queue.
- Mark, compact, promote
- A collection marks every reachable object, reclaims the rest, may slide survivors together (updating references), and moves survivors up one generation.
- Generation
- An age group of objects: gen 0 for new objects, gen 1 for survivors of one collection, gen 2 for long-lived objects. Young generations are collected far more often.
- Large object heap (LOH)
- Where objects of 85,000 bytes or more are allocated. It is collected together with generation 2.
Notes and sources
- The addresses (0xA000, 0xA040, 0x8000) are made up and shortened, and the gaps between them are not to scale.
- GC.Collect(0) is here only to make the collection happen at a known line. Real programs should almost never call GC.Collect: the runtime tunes when to collect far better.
- The picture shows the classic layout: survivors slide into gen 1. Since .NET 7 the heap is organised in regions, and a whole gen 0 region can also simply become gen 1; the GC may also sweep without compacting. Either way the object survives and its generation becomes 1.
- Order has no reference fields, so marking stops at Order(1). A real mark phase follows every reference field of every object it reaches, all the way down.
- Before a collection, all managed threads except the one that triggered it are suspended. Background garbage collection lets most gen 2 work run while the program keeps going; gen 0 and gen 1 collections are always blocking (foreground) ones, and usually quick.
- The GC only manages memory. Files, sockets and other unmanaged resources must be released with Dispose; a using statement or declaration calls it for you. A finalizer is only a safety net and makes its object survive one extra collection.
- The program is real C# (top-level statements; nullable and implicit usings on, as in dotnet new console). Built and run, it prints 1.
- Microsoft Learn: Fundamentals of garbage collection
- Microsoft Learn: Garbage collection overview
- Microsoft Learn: The large object heap on Windows systems
- Microsoft Learn: GC.Collect method
- Microsoft Learn: GC.GetGeneration method
- Microsoft Learn: Induced collections
- Microsoft Learn: Cleaning up unmanaged resources
- Microsoft Learn: Implement a Dispose method
- Microsoft Learn: Finalizers (C# programming guide)
- Microsoft Learn: Records (C# reference)
Quiz Unlocks after the last step.