Generational ZGC
ZGC learned the generational trick in 21, cutting its CPU and memory cost sharply.
Open this lesson in the learning hubKey points
- ZGC already gave sub-millisecond pauses, but scanned the whole heap every cycle.
- Most objects die young, so scanning old survivors repeatedly is wasted work.
- JEP 439 added young and old generations to ZGC, collecting the young part far more often.
- The result is the same tiny pauses at meaningfully lower CPU and heap overhead.
- In 21 you opt in with
-XX:+UseZGC -XX:+ZGenerational; later releases made it the default.
Example
public class Main {
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
System.out.println("max heap MB : " + rt.maxMemory() / (1024 * 1024));
long before = rt.totalMemory() - rt.freeMemory();
// Churn: almost all of this dies immediately - exactly what a young gen is for
StringBuilder keep = new StringBuilder();
for (int i = 0; i < 200_000; i++) {
String tmp = "garbage-" + i;
if (i % 50_000 == 0) { keep.append(tmp).append(' '); }
}
long after = rt.totalMemory() - rt.freeMemory();
System.out.println("used before : " + before / 1024 + " KB");
System.out.println("used after : " + after / 1024 + " KB");
System.out.println("survivors : " + keep);
System.out.println("GC in use : " +
java.lang.management.ManagementFactory.getGarbageCollectorMXBeans()
.stream().map(b -> b.getName()).toList());
}
}
Generational ZGC kept the pause guarantee and stopped paying for it with wasted scanning.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Java 21 Course course, and every lesson in it is listed on the Java 21 Course contents page.