Concepts · Java fundamentals

Garbage collection

Generational GC, the main collectors, and how to reason about pauses.

What counts as garbage

An object is collectable when it can’t be reached from a GC root: local variables on thread stacks, static fields, active threads and JNI references. Reachability, not reference counting, so cycles are collected fine.

Generational heap

Most objects die young, so the heap is split:

  • Young generation: Eden (new objects) + two Survivor spaces. A minor GC copies live objects from Eden to a survivor; objects that survive enough cycles are promoted.
  • Old generation: long-lived objects, collected less often (major / full GC).

Copying the few survivors is cheap, which is why young collections are fast.

Phases

Mark live objects → sweep the dead → compact to remove fragmentation. A stop-the-world pause halts application threads; modern collectors do most of the marking concurrently.

Collectors

CollectorIdeaUse when
Serialsingle threadtiny heaps, one CPU
Parallelmany threads, stop-the-worldthroughput matters more than pauses (batch)
G1 (default since Java 9)heap in regions, collects the most garbage first, pause-time targetmost services
ZGC / Shenandoahalmost everything concurrent, pauses < a few mslarge heaps, latency-sensitive

Reasoning about GC in production

  • Frequent full GCs or growing old gen after each GC → likely a memory leak (e.g. an unbounded cache, listeners never removed).
  • Tune by sizing the heap (-Xms/-Xmx) and setting a pause goal (-XX:MaxGCPauseMillis) before touching anything else.
  • Read GC logs (-Xlog:gc*) and watch allocation rate; allocating less is the best tuning.

Reference types

Strong (normal) · Soft (cleared under memory pressure, for caches) · Weak (cleared at next GC, WeakHashMap) · Phantom (cleanup after finalisation).