The last part covers what changes when the JVM runs in a container, where memory management is heading with Project Leyden, and a cheat sheet of the flags from the whole series.
Container and Cloud Considerations
The Container Challenge
Containers break assumptions that traditional GC tuning relied on:
- CPU limits: GC threads may exceed cgroup limits, causing throttling
- Memory limits: OOM killer terminates containers before GC can react
- Noisy neighbors: Shared resources affect GC timing
Container-Optimized Settings
# Java 17+ container awareness
java -XX:+UseContainerSupport \
-XX:MaxRAMPercentage=75.0 \
-XX:InitialRAMPercentage=75.0 \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=100 \
MyApp
# ZGC in Kubernetes (Java 23+ - generational by default)
java -XX:+UseZGC \
-XX:MaxRAMPercentage=75.0 \
-XX:+AlwaysPreTouch \
MyAppCloud-Native Recommendations
- AWS Lambda: Serial (the JVM picks it with little memory and one core). Minimal cold start.
- Kubernetes: ZGC or G1. Set resource limits appropriately.
- Serverless: N/A (platform managed). Focus on allocation reduction.
- EC2/VMs: Any. Full control, tune to workload.
Epilogue: The Art of Memory Management
Garbage collection in the JVM is not a necessary evil - it’s a sophisticated automation that eliminates entire classes of bugs (memory leaks, double frees, dangling pointers) that plague manual memory management languages. The cost is unpredictability, but modern collectors have reduced that cost to negligible levels for most applications.
The key insights:
- Start with defaults: G1 is the default because it works well enough for most
- Measure before tuning: Don’t optimize what you haven’t measured
- Match collector to constraints: Throughput? Parallel. Latency? ZGC. Balanced? G1
- Size your heap correctly:
-Xms=-Xmxin production, always - Monitor continuously: GC behavior changes with workload patterns
Your application is a symphony. The garbage collector ensures every musician - every object - enters and exits at the right moment. Choose your conductor wisely, tune your instruments properly, and your performance will resonate with users.
The Road Ahead: Project Leyden and AOT Profiling
The JVM continues to evolve toward even more intelligent memory management. Project Leyden’s AOT (Ahead-of-Time) profiling (JEPs 514 and 515) represents a significant advancement that indirectly benefits all garbage collectors. By capturing and reusing profiling data across JVM restarts, AOT profiling reduces the JIT compilation warmup period. This translates to reduced allocation rate variance during the application’s early phase, which means less pressure on the young generation and more predictable GC behavior from the moment your application starts serving traffic. For latency-sensitive services, this elimination of warmup-induced allocation spikes is another step toward truly consistent performance.
Updated for February 2026. JVM garbage collection has evolved rapidly - ZGC is generational by default since Java 23, non-generational ZGC was removed in Java 24 (JEP 490), Shenandoah added generational mode in Java 25 (JEP 521), and G1 gained compiler barrier optimizations in Java 24 (JEP 475). The future points toward zero-configuration, self-tuning collectors, but understanding these fundamentals remains essential for every JVM developer.
Quick Reference
Collector Selection Flowchart
What matters most?
- ThroughputParallel
- LatencyZGC or Shenandoah
- FootprintSerial
- BalanceG1, the default
The same decision as in part 1, which explains each priority.
JVM Flags Cheat Sheet
- Enable G1
- Enable ZGC
- Enable Shenandoah
- Enable Parallel
- Target pause time (G1, Parallel)
- Fixed heap size
- Container support (on by default)
- GC logging
Further Reading
JVM Architecture & Performance:
- JVM: The Silent Revolution - Java 25’s Compact Object Headers, Project Leyden, and zero-code-change performance gains
- Java Performance: The Definitive Guide - Scott Oaks
Garbage Collector Documentation:
- ZGC Wiki - Official ZGC documentation
- Shenandoah Wiki - Shenandoah project page
- G1 GC Tuning Guide - Oracle’s official guide for Java 25
JEP References (Java 24-25):
- JEP 519: Compact Object Headers - Object header compression
- JEP 521: Generational Shenandoah - Generational mode for Shenandoah GC
- JEP 474: Generational ZGC - Generational ZGC, default since Java 23
Research and Case Studies:
- Chirumamilla, P. et al. “Java Virtual Threads: a Case Study.” InfoQ, July 2024. Production analysis of virtual thread memory behavior and GC implications.
Master the orchestra of memory management, and your JVM applications will perform with the precision of a world-class symphony - responsive, efficient, and beautifully tuned to the demands of your users.