G1 and ZGC
G1 balances throughput against pause time. ZGC trades some throughput for pauses under a millisecond.
Open this lesson in the learning hubKey points
- G1 is the default on anything with 2+ cpus and roughly 1.8 GB. It divides the heap into many equal-sized regions.
- G1 collects the regions holding the most garbage first - the garbage-first in the name - and works towards a pause target.
-XX:MaxGCPauseMillis=200is a goal, not a promise. Ask for less and G1 collects smaller batches more often.- ZGC, enabled with
-XX:+UseZGC, does nearly everything concurrently. Pauses stay under a millisecond at any heap size. - ZGC gives up a little throughput and wants some extra memory. Take that deal when tail latency matters more than raw speed.
- JDK 21 adds generational ZGC behind
-XX:+ZGenerational. On a tiny container the Serial collector is still the right answer.
Example
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
public class Main {
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
System.out.println("cpus = " + rt.availableProcessors()
+ ", max heap = " + (rt.maxMemory() >> 20) + " MB");
System.out.println();
System.out.println("collectors running right now:");
for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) {
System.out.println(" " + gc.getName());
}
System.out.println();
System.out.println("G1 Young/Old Generation -> G1, the default on server-class machines");
System.out.println("ZGC Cycles / ZGC Pauses -> ZGC, switched on with -XX:+UseZGC");
System.out.println("Copy + MarkSweepCompact -> Serial, chosen on small containers");
}
}
G1 for most services. ZGC when a 200 ms pause would count as a bug.
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 JVM course, and every lesson in it is listed on the JVM contents page.