How does garbage collection work in the JVM (generational hypothesis, young/old generation)?

10 minadvancedgarbage-collectiongenerational-gcjvm

Quick Answer

Most JVM garbage collectors rely on the generational hypothesis — most objects die young — and 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 the vast majority of garbage actually accumulates.

Detailed Answer

Most production JVM collectors (Parallel GC, G1, and others) are built around the generational hypothesis: empirically, the vast majority of 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 — 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) are promoted ("tenured") into the old generation, on the assumption they're likely to be long-lived. The old generation is larger and collected far less often, via a major/full GC — 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) storing class metadata, separate 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 — a major reason modern low-latency collectors like G1 and ZGC were built to minimize or largely eliminate full-heap pause times.

Related Resources