Skip to main content

Garbage Collection (GC) in the JVM – Optimization and Configuration

java-garbage-collector.png

Objective

Reduce GC (Garbage Collection) pauses in Java applications by choosing the right garbage collector (G1, ZGC, Shenandoah) and configuring the JVM to balance latency, throughput, and memory usage.


What is Garbage Collection?

The Garbage Collector in the JVM:

  • Identifies unused (unreferenced) objects
  • Frees up memory they occupy
  • Can introduce pause times if misconfigured, affecting performance

Why It Matters for Performance

In systems such as:

  • Real-time applications (games, finance)
  • High-throughput systems (web apps, microservices)
  • Low-latency systems (Kafka, databases, event processing)

A poorly configured GC can:

  • Trigger long "stop-the-world" pauses
  • Cause CPU spikes
  • Degrade user experience and system responsiveness

Types of Garbage Collectors

CollectorSinceAdvantagesDisadvantagesWhen to Use
Serial GCJava 1.2SimpleLong pausesSmall apps, development
Parallel GCJava 1.4High throughputLong pausesBatch jobs, throughput-focused apps
G1 GCJava 9Predictable pauses, balancedNot ultra-low latencyWeb servers, general purpose
ZGCJava 11+Ultra-low latency (<10 ms)Less tuning flexibilityLow-latency systems (finance, APIs)
ShenandoahJava 12+Similar to ZGC, low latencyLess portable (Red Hat)Real-time, low-latency apps

How to Choose the Right GC

GoalRecommended Collector
Balanced performanceG1 GC
Ultra-low latency (<10ms)ZGC or Shenandoah
Max throughput (batch)Parallel GC

JVM Configuration Examples

G1 GC (Balanced)

-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:InitiatingHeapOccupancyPercent=45
-XX:+ParallelRefProcEnabled
-Xms2g -Xmx4g
  • MaxGCPauseMillis: Target max pause duration
  • InitiatingHeapOccupancyPercent: Threshold to trigger GC

ZGC (Ultra-low latency)

-XX:+UseZGC
-Xmx4g -Xms4g
  • Suitable for very low-latency needs
  • No tuning required
  • Requires Java 11+

ToolPurpose
JVisualVM / JConsoleView GC events and memory usage live
GC Logs (-Xlog:gc*)Detailed analysis of GC behavior
Java Flight RecorderLow-overhead JVM profiling
Prometheus + GrafanaReal-time JVM metrics visualization

Common Mistakes to Avoid

MistakeConsequence
Ignoring GC logsCannot analyze or debug GC behavior
Using wrong GC for the workloadUnnecessary long pauses
Incorrect heap sizingToo small → frequent GC; too big → longer scans
Excessive object allocationGC overload (especially young gen)
Using finalize()Slows down GC, discouraged in modern Java

Business Use Case Example

Case: Online PDF Generation System

  • Problem: Generates many temporary objects (~100 MB per document)
  • Effect: Frequent GC, noticeable user delays
  • Solution:
    • Switched to G1 GC
    • Configured -XX:MaxGCPauseMillis=150
    • Reused memory buffers to avoid GC pressure
    • Set up Prometheus + Grafana for JVM monitoring

Further Reading


Summary

  • GC is critical to Java application performance and reliability
  • Choose the collector that matches your latency or throughput needs
  • G1 is a solid general-purpose collector
  • ZGC and Shenandoah are best for latency-sensitive systems
  • Always monitor GC behavior in production and test under load