Garbage Collectors in Java

Naveen AnamaneniUpdated · 4 min read

The HotSpot JVM ships with several garbage collectors, each balancing three goals differently: throughput (how much of the CPU goes to your program instead of GC), latency (how long the application pauses), and memory footprint. You choose one with a command-line flag. In Java 25, the default on most machines is G1, a good all-rounder, while ZGC keeps pauses under a millisecond even on huge heaps. In this lesson, you will learn the five collectors and how to choose between them.

The Collectors

CollectorFlagHow it worksPausesBest for
Serial-XX:+UseSerialGCOne thread; stops the application for every collectionLongestSmall heaps, single-core machines, small containers
Parallel-XX:+UseParallelGCMany threads, but still stops the applicationMediumBatch jobs where total throughput matters most
G1 (default)-XX:+UseG1GCSplits the heap into regions; collects the most garbage-filled regions first; marks concurrentlyShort, with a target (-XX:MaxGCPauseMillis, default 200 ms)Most applications
ZGC-XX:+UseZGCGenerational (Java 21+); marks and moves objects concurrently using colored pointersUnder 1 ms, independent of heap sizeLarge heaps and latency-sensitive services
Shenandoah-XX:+UseShenandoahGCConcurrent compactionVery shortLow-latency services (available in OpenJDK builds)

CMS, an older low-pause collector, was removed in Java 14.

From stop-everything collectors to mostly concurrent ones

Example: Which Collector Is Running?

Let's see an example that reports the active collector. Run it with different flags to see each collector's parts.

WhichGc.java▶ Try it
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
 
public class WhichGc {
    public static void main(String[] args) {
        for (GarbageCollectorMXBean gc :
                ManagementFactory.getGarbageCollectorMXBeans()) {
            System.out.println(gc.getName());
        }
    }
}
Output
G1 Young Generation
G1 Concurrent GC
G1 Old Generation

Run with each collector's flag, the same program prints:

Terminal output
-XX:+UseSerialGC      Copy, MarkSweepCompact
-XX:+UseParallelGC    PS MarkSweep, PS Scavenge
-XX:+UseG1GC          G1 Young Generation, G1 Concurrent GC, G1 Old Generation
-XX:+UseZGC           ZGC Minor Cycles, ZGC Minor Pauses, ZGC Major Cycles, ZGC Major Pauses
-XX:+UseShenandoahGC  Shenandoah Pauses, Shenandoah Cycles

Explanation: With no flag, the JVM chose G1. The other lines come from running the program with each flag (the names are joined on one line here to save space). Serial and Parallel name their young collector ("Copy", "PS Scavenge") and old collector separately. ZGC and Shenandoah report concurrent cycles separately from their short pauses.

How to Choose

  1. Start with the default (G1) and measure.
  2. If pauses are too long for your service, try ZGC.
  3. If the job is a batch where only total time matters, try Parallel.
  4. For tiny containers (one CPU, small heap), the JVM may pick Serial itself, and that's fine.

Common Mistakes

Tuning many GC flags at once. Change one thing, measure, repeat.

Choosing ZGC for small batch jobs. Its concurrent work costs some throughput; Parallel may finish sooner.

Looking for CMS. It was removed in Java 14.

Interview Corner

What garbage collectors are available in Java, and how do you choose?

HotSpot offers Serial (single-threaded, stop-the-world, for small heaps), Parallel (multi-threaded stop-the-world, for throughput), G1 (region-based, mostly concurrent marking with pause-time goals, the default), ZGC (concurrent, generational since Java 21, sub-millisecond pauses even for terabyte heaps) and Shenandoah (concurrent compaction, low pause). Start with G1; choose ZGC or Shenandoah when latency matters, Parallel when throughput matters and pauses don't, and Serial for very small footprints. Decide based on measured GC logs.

Practice

  1. Easy: Run WhichGc with -XX:+UseZGC and -XX:+UseSerialGC and compare the names.
  2. Harder: Run a program that creates lots of garbage with -Xlog:gc under G1, Parallel and ZGC, and compare the reported pause times.

Quick check: Garbage collectors

4 questions
1Which collector is the default in Java 25 on most machines?
2Which collector keeps pauses under a millisecond on huge heaps?
3Which collector suits a batch job where only total time matters?
4Which collector was removed in Java 14?

Key Takeaways

Was this tutorial helpful?

Lesson 441 of 482