⚙️ JVM Internals & Memory · Advanced

Garbage collectors in Java

Serial, Parallel, G1 (default), ZGC, Shenandoah and their trade-offs.

🧩 The mysterySame app, same heap, one flag changed: GC pauses drop from 200 ms to under a millisecond. What did that flag swap?

No collector wins everything

Collectors trade off three things: throughput (how much CPU goes to your code), latency (how long pauses are) and footprint (extra memory). You choose by workload, with a flag like -XX:+UseZGC.

The simple ones

Serial uses a single GC thread: fine for tiny heaps and small containers. Parallel uses many threads and stops the app while it works, for maximum throughput: great for batch jobs where pauses don't matter.

java -XX:+UseSerialGC   ...  // tiny heaps
java -XX:+UseParallelGC ...  // batch jobs

G1, the default

G1 has been the default since Java 9, replacing Parallel. It's region-based and works toward a pause-time goal, balancing throughput and latency. If you pass no GC flag on a typical server, you get G1.

ZGC and Shenandoah

ZGC and Shenandoah mark and relocate objects concurrently, while your threads keep running. Pauses stay very short and don't grow with heap size. ZGC is generational by default since Java 23, and Java 24 removed its old non-generational mode.

🔮 Predict it

Pick for a trading API

A trading API with a 64 GB heap must keep GC pauses under 1 ms. Which collector fits best?

  1. ZGC
  2. Parallel
  3. Serial
Show the answer

ZGC. It does almost all its work concurrently, so pauses stay tiny even on huge heaps. Parallel and Serial stop the app for the whole collection.

⚠️ The trap

Copy-pasted flags

Old tutorials say -XX:+UseConcMarkSweepGC. The CMS collector was removed in Java 14; recent JDKs refuse to start with that flag. Use G1 or ZGC instead.

java -XX:+UseConcMarkSweepGC -jar app.jar
// Unrecognized VM option (recent JDKs)
💼 In the real world

Choosing in practice

Batch ETL job: Parallel. Typical REST service: stick with G1. Latency-critical services or very large heaps: ZGC. On very small machines the JVM may even pick Serial on its own. Whatever you choose, compare GC logs before and after: pauses, throughput and memory.

Key takeaways

  1. Serial: single-threaded, small heaps
  2. Parallel: best throughput for batch jobs
  3. G1: default since Java 9, region-based, pause-time goal
  4. ZGC / Shenandoah: concurrent, very low pauses
🤯 Did you know?

Shenandoah was created at Red Hat and later contributed to OpenJDK, while ZGC came from Oracle: two teams, same goal of tiny pauses.

Practice questions

A trading API with a 64 GB heap must keep GC pauses under 1 ms. Which collector fits best?

  1. ZGC
  2. G1 with default settings
  3. Serial
  4. Parallel
Check your answer

ZGC. ZGC is designed for very low pause times that don't grow with heap size, even for multi-terabyte heaps.

With no GC flag on a typical server machine (Java 9+), which collector does HotSpot use?

  1. Serial
  2. Parallel
  3. G1
  4. ZGC
Check your answer

G1. G1 replaced Parallel as the default in Java 9. Other collectors are selected with flags like -XX:+UseZGC.

The GC decides when an object dies. But can you tell it "this one is optional"? Next: soft, weak and phantom references.