Roots, reachability, and tri-color invariant
Basics | 7-minute read
- Roots: stacks, registers, globals; tracing finds reachable objects.
- Tri-color: white (unreached), gray (reached, not scanned), black (scanned).
- Write/read barriers preserve invariants during mutator execution.
Invariant: no black points to white (Dijkstra) or no white accessible from black (Yuasa)
Mark–sweep GC
Classic | 8-minute read
- Mark phase: trace from roots; Sweep phase: return unmarked objects to free lists.
- Non-moving; can fragment; simple to integrate with free-list allocators.
- Incremental variants rely on barriers and bitmaps.
mark(rootset)
sweep(heap)
Copying GC (Cheney)
Moving | 8-minute read
- Semi-space: from-space → to-space using a scan pointer; compacts and improves locality.
- Requires forwarding pointers; doubles memory reservation for semi-spaces.
- Great for short-lived objects (nursery/young gen).
while scan < to_end: for each ref in obj(scan): if in from-space then copy & forward
Generational GC and remembered sets
Young/Old | 9-minute read
- Empirical: most objects die young; collect young frequently, old rarely.
- Card marking/remembered sets track old→young pointers (write barriers).
- Minor vs major GCs; promotion thresholds and survivor spaces.
write barrier: card_table[addr >> card_shift] = DIRTY
Concurrent/incremental GC and barriers
Low-pause | 8-minute read
- Concurrent marking with SATB (Snapshot-At-The-Beginning) or incremental update.
- Barriers: write (post/pre), read barriers (e.g., Brooks, ZGC load barriers).
- Compacting collectors: sliding compaction vs evacuations.
Exercises
Hands-on | 8-minute read
- Build a toy copying collector (semi-space) for a simple object graph.
- Add a generational layer with a card table; observe minor vs major GC behavior.
- Experiment with pause targets and region sizes to mimic G1-style choices.
Different collectors optimize different objectives—pick the one that matches your latency and throughput goals.