How does garbage collection work in the JVM (generational hypothesis, young/old generation)?
Quick Answer
Most JVM garbage collectors rely on the generational hypothesis: most objects die young. They split the heap into a small Young Generation, further split into Eden and two Survivor spaces, for frequent, fast minor GCs, and a larger Old Generation for objects that survive several minor collections, collected less often via a major/full GC. This lets the collector spend most of its effort on the young generation, where most garbage actually accumulates.
Detailed Answer
Most production JVM collectors (Parallel GC, G1, and others) are built around the generational hypothesis: most objects become garbage very shortly after being allocated — think loop-local temporaries, short-lived request objects — while a small minority survive much longer. Splitting the heap by object age lets the collector focus effort where garbage actually accumulates.
Young Generation: where new objects are allocated. Subdivided further:
- Eden space: where nearly all new objects are born.
- Two Survivor spaces (S0/S1): objects that survive an Eden collection are copied into one survivor space. On the next collection they're copied to the other, alternating. This "copying collector" approach is cheap because it only touches live objects, not garbage.
A minor GC collects only the young generation. It's fast and frequent, because the young gen is small and most objects there are already dead.
Old (Tenured) Generation: objects that survive enough minor GCs — their "age" counter crosses a threshold — get promoted ("tenured") into the old generation, on the assumption they're likely long-lived. The old generation is larger and collected far less often, via a major/full GC, which is typically more expensive since it scans a much bigger, longer-lived object graph.
Heap
├── Young Generation
│ ├── Eden (most objects allocated here)
│ ├── Survivor 0
│ └── Survivor 1
└── Old Generation (long-lived, promoted objects)
There's also Metaspace (off-heap since Java 8, replacing PermGen), which stores class metadata separately from both generations.
This generational design is why minor GCs are usually fast — sub-millisecond to a few ms pauses — while a full GC, especially with older collectors like Parallel GC, can cause noticeably longer "stop-the-world" pauses. That's a major reason modern low-latency collectors like G1 and ZGC were built: to minimize or largely eliminate full-heap pause times.