How memory gets freed
Every program has to give memory back. The question is who does it, when, and on which thread. Four languages answer it four different ways, and each answer shows up on the thread lanes.
Rust: the owner frees it, right away
No collector at all. A value is freed when its owner goes out of scope, before the next line runs, on the thread that owns it. A value moved into a thread is freed by that thread.
No garbage collector. Each value is freed by its owner, at a line you can point to, on the owner's thread.
Python: reference counts, plus a collector for cycles
CPython frees an object the moment its last reference goes, inside the del. Objects that point at each other never reach a count of 0, so they wait in memory until the cycle collector runs.
del frees an object the moment its last reference goes. Two objects that point at each other stay in memory until the cycle collector runs.
Go: a collector that runs alongside you
Go stops the world briefly to start a collection, marks while your goroutines keep running, and stops once more to finish. Most of a collection is the concurrent mark. The goroutine that allocates fast starts the collection and is made to help mark.
Two brief stop-the-world steps bracket a concurrent mark. The goroutine that allocates starts the collection and helps mark; the others barely notice.
Java: a pause that stops every thread
When an allocation doesn’t fit, that thread asks for a young collection. G1 runs it at a safepoint, so every Java thread stops, including ones that never allocate, while GC worker threads copy the live objects in parallel.
When main's allocation doesn't fit, it asks for a young collection. Every Java thread stops at a safepoint while GC threads copy the live objects.
Side by side
| Who frees memory | When | Do your threads stop? | |
|---|---|---|---|
| Rust | the owner, at the end of its scope | at a line you can see | no |
| Python | reference counting; the cycle collector for cycles | when the last reference goes; cycles later | not for reference counting |
| Go | GC worker goroutines, with help from the allocating one | when a collection starts | twice, briefly, per collection |
| Java (G1 young) | GC worker threads | when an allocation doesn’t fit | yes, for the whole pause |
Common questions
Which languages stop the world for garbage collection?
In these timelines, Java's G1 young collection stops every Java thread at a safepoint, and Go stops the world twice per collection around a concurrent mark. Rust has no collector, and Python frees most objects by reference counting, without one.
Does Rust have a garbage collector?
No. Each value is freed when its owner goes out of scope, before the next line runs, on the owner's thread.
Why does Python have a garbage collector if it uses reference counting?
Reference counting can't free objects that refer to each other. After del, such a cycle stays in memory until the cycle collector runs.
Every timeline here is checked against a real program in CI. How we verify