Skip to content
Back
JVM internals

Garbage Collection in Containers, and What Comes Next

Container-aware heap sizing, cloud settings, a cheat sheet of GC flags, and where Project Leyden takes JVM memory management.

Michał Artur Marciniak

3 min read

On this page
  1. Container and Cloud Considerations
  2. Epilogue: The Art of Memory Management
  3. Quick Reference

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:

  1. CPU limits: GC threads may exceed cgroup limits, causing throttling
  2. Memory limits: OOM killer terminates containers before GC can react
  3. Noisy neighbors: Shared resources affect GC timing

Container-Optimized Settings

Shell
# 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 \
     MyApp

Cloud-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:

  1. Start with defaults: G1 is the default because it works well enough for most
  2. Measure before tuning: Don’t optimize what you haven’t measured
  3. Match collector to constraints: Throughput? Parallel. Latency? ZGC. Balanced? G1
  4. Size your heap correctly: -Xms = -Xmx in production, always
  5. 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

Choosing a garbage collectorFlowchart with 5 nodes and 4 connectionsThroughputLatencyFootprintBalanceWhat matters most?What matters most?ParallelParallelZGC or ShenandoahZGC or ShenandoahSerialSerialG1, the defaultG1, the default

What matters most?

  • ThroughputParallel
  • LatencyZGC or Shenandoah
  • FootprintSerial
  • BalanceG1, the default
Pick the priority from the three dimensions above. When none of them dominates, stay with G1.

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:

Garbage Collector Documentation:

JEP References (Java 24-25):

Research and Case Studies:


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.