How Java Garbage Collection Works

Intermediate
8 min read· Backend & Databases

Garbage collection (GC) is how the JVM automatically frees memory you no longer use. Instead of calling free() like in C, you just stop referencing an object and the collector reclaims it. Modern JVMs use generational collection — most objects die young, so the heap is split into a Young Generation (collected often and fast) and an Old Generation (collected rarely). Collectors like G1GC, ZGC, and Shenandoah trade throughput against pause time, letting you tune Java for either batch jobs or ultra-low-latency APIs.

Think of GC as an automatic cleaning crew

Imagine a workshop where you leave tools lying around. A cleaning crew (the GC) periodically checks which tools are still connected to someone actively working (reachable from a live reference) and puts away everything else. New tools go on a small, frequently-swept front bench (Eden); tools you keep using get moved to long-term storage (Old Generation) that is cleaned far less often. Smart crews clean the busy front bench in the background so you barely notice a pause.

Step by Step

1 / 5

Key Concepts

GC Roots

The starting points for reachability: local variables on thread stacks, static fields, and JNI references. An object is "live" only if a chain of references leads to it from a root; otherwise it is garbage.

Stop-the-World (STW) Pause

A moment when the JVM pauses all application threads so the collector can safely scan references. Minimising STW time is the main goal of modern low-latency collectors like ZGC.

Generational Hypothesis

The empirical observation that most objects die young. It justifies splitting the heap so the frequently-collected Young Generation stays small and cheap to scan.

G1 vs ZGC vs Shenandoah

G1GC targets balanced throughput and predictable pauses (default since Java 9). ZGC and Shenandoah are concurrent collectors targeting sub-millisecond pauses on multi-gigabyte-to-terabyte heaps, ideal for latency-sensitive services.

Key Facts

  • Setting -Xms equal to -Xmx pre-allocates the heap and avoids pauses caused by the JVM resizing it under load.
  • A rising "GC overhead" — the JVM spending most of its time collecting but reclaiming little — usually signals a memory leak, not a tuning problem.
  • ZGC (production-ready since Java 15) keeps pause times independent of heap size, so a 4GB heap and a 4TB heap pause about the same.

Real-World Applications

Tuning a low-latency API

For services with strict P99 latency, switch to ZGC (-XX:+UseZGC), fix the heap size (-Xms = -Xmx), and watch pause times with -Xlog:gc*. This trades a little throughput for consistent, sub-millisecond GC pauses.

Diagnosing long pauses

If users see periodic freezes, enable GC logging and look for full GCs. Frequent full GCs mean the Old Generation is under pressure — often from a leak (unbounded caches, uncleared ThreadLocals) or an undersized heap.

Frequently Asked Questions

Can I force garbage collection in Java?

You can call System.gc(), but it is only a hint — the JVM may ignore it. Relying on it is an anti-pattern. In production, let the collector run on its own schedule and tune it with flags instead of forcing collections.

Does garbage collection prevent all memory leaks?

No. GC frees only unreachable objects. If you keep references alive unintentionally — static collections that grow forever, listeners never removed, ThreadLocal values not cleared — those objects stay reachable and are never collected. That is a Java memory leak.

What is the difference between minor and major GC?

A minor GC collects only the Young Generation (Eden + Survivor) and is fast because most young objects are dead. A major (or full) GC collects the Old Generation too and is slower, typically causing longer pauses.

Which garbage collector should I use?

For most applications, the default G1GC is a good balance. Choose ZGC or Shenandoah when you need very low, predictable pause times on large heaps. Use Parallel GC for batch/throughput workloads where pauses do not matter.

Related Topics