Who clears away data nobody needs any more, and when? The cleaner walking the storeroom only takes boxes nobody claims — a box whose ticket someone still holds is never touched.
Every time a program makes new data it takes free space from the heap: allocation. If nothing is ever reclaimed the heap fills and the program dies. This chapter shows how a computer decides that data is "done with", and what a garbage collector actually does. Follow a short loop that loads photos and makes thumbnails.
The computer cannot read your intent, so it uses a mechanical rule: start from live variables, follow references; anything you can reach is alive, anything you cannot is garbage. Overwrite img with a new photo's address and the previous box becomes unreachable — not erased, just unreachable. That is the box that dims and gets struck through.
The classic collector marks everything reachable from the stack roots, then sweeps up the unmarked boxes and returns their space. So GC never removes what "looks useless" — only what is provably unreachable.
If the program kept mutating references mid-mark the bookkeeping would break, so collectors briefly stop your code. That stop is the GC pause, and it grows with heap size and live-set size. It is one reason server latency occasionally spikes.
Memory still fills in GC languages, for two reasons: allocating faster than collecting, or someone holding references so GC is not allowed to reclaim. Caches that never evict, lists that keep finished requests, long-lived objects pinning short-lived data — all of that is retention.
1main() {2 album = []PC ◀3 for i in 0..2 {4 img = load("photo" + i)5 thumb = resize(img)6 album.push(thumb)7 }8 show(album)9}
An empty array is created on the heap (@1); album holds its tag. This chapter asks one question — why does memory fill up?
Try it in the simulator
Terms in this chapter
Why it evolved this way
Programmers used to free memory by hand, and it was the most-bugged code in history — double frees, use-after-free, forgotten frees. So most modern languages adopted reachability-based collection. The price is pauses and some CPU overhead.
GC only takes what nothing can reach — hold a reference and it can never take it.
The remaining problem
So what makes code hold references for a long time? The next chapter's waiting is a prime culprit →