Build Log

Tracking the process of building — systems, skills, and ideas that evolve over time.

Healthy vs Non-Healthy Garbage Collection Behavior In The JVM

Introduction

Ever watched your Java service slow to a crawl for no clear reason?
Often, the culprit isn’t your code — it’s your garbage collector gasping for air.

Garbage collection (GC) is the JVM’s built-in memory management mechanism, automatically reclaiming space from unreachable objects so you can focus on writing logic instead of worrying about leaks.
But GC activity is more than just a background process — it’s like your application’s heartbeat. Smooth, predictable GC behavior signals healthy memory use, while erratic or frequent GC events often reveal deeper performance issues: leaks, excessive allocation, or poor tuning.

In this post, we’ll explore what defines healthy vs. unhealthy GC behavior, how to interpret heap usage patterns, and how to correct GC issues before they impact performance.


What does "healthy" GC behavior look like

When the GC is functioning optimally, you'll see a stable rhythm of memory allocation and reclamation.

Typical Pattern

  1. The heap gradual fills as the application allocates objects.
  2. A GC event (young or full) reclaims unused memory.
  3. Heap usage drops, and the cycle repeats predictably.

This creates the characteristic "saw-tooth" pattern in heap usage charts - often a sign of a healthy application.

"Heap usage will keep rising; once a Full Garbage collection ... occurs memory utilization drops all the way to the bottom ... It indicates that the application is in a healthy state & not suffering from any sort of memory problems." DZone: Interesting Garbage Collection Patterns

Traits of a Healthy GC

Note: With modern concurrent collectors like G1GC, ZGV, and Shenandoah, the saw-tooth pattern may appear smoother since these collectors perform most work concurrently, reducing large visibility drops.


What does "Unhealthy" GC behavior Look Like?

Unhealthy GC behavior indicates that your application or JVM configuration is struggling to manage memory efficiently.

Common Symptoms

Symptom Description Likely Causes
Frequent Full GCs Full GCs happen seconds apart, consuming CPU and causing pauses Heap to small, excessive allocation, old-gen promotion pressure.
Rising Heap Baseline Memory after GC keeps growing after GC. Objects are still strongly referenced.
GC Thrashing JVM spends more time in GC than running the app. Small heap, too amny short-lived objects, mis-tuned GC parameters
Promotion Failures / OOM Objects move prematurely to old generation, eventually OOM Survivor space exhaustian, high allocation churn.

Visual Examples: Healthy vs Unhealthy Patterns

Pattern Description Typical Cause
Healthy Saw-Tooth Heap rises and falls predictably with GC cycles Balanced allocation and reclaimation
Rising Baseline Each GC leaves more memory retained Memory leak or poor caching logic.
Flag / No Drop Heap stays high even after GC Retained strong references.
Frequent Spikes Constant GCs reclaim little memory Heap too small or allocation too fast

Diagnosing GC Health

Understanding GC health requires monitoring metrics, and log analysis.

GC Logs

Enables GC logging in modern JVMs:

java -Xlog:gc*:file=gc.log:time,uptime,level,tags MyApp
Parameter Description
java Runs the Java Virtual Machine (JVM).
-Xlog:gc* Enables detailed logging for all garbage collection events.
file=gc.log Writes logs to a file (gc.log) for later analysis.
time Includes wall-clock timestamp of each event.
uptime Adds time since JVM startup.
level Includes log severity (info, warning, etc.).
tags Includes event tags (gc, heap, pause, etc.).
MyApp The Java class containing the main method to run.

Monitoring Tools

Tool Description
VisualVM live heap and GC charts
Java Mission Control (JMC) Advanced Profiling And Flight Recordings
Grafana & Prometheus Dashboards

Key Metrics to Watch

Metric What It Tells You Health Range / Guidance
GC Pause Time Duration of stop-the-world events. <200ms for latency specific systems.
GC Frequency How ofen the GCs occur Should scale with allocation rate, not spike randomly.
Heap after GC Post-collection heap usage. Should stay roughly stable over time.
Allocation Rate Object creation speed Excessive rates -> rune caching or reuse objects

Keeping Your GC Healthy

Right-Size Your Heap

  • Set -Xms and -Xmx to match actual usage.
  • Avoid setting them too small - causes frequent GCs.
  • Avoid excessive heap - delays leak detection.

Pick the Right GC Algorithm

  • G1GC (default since JDK 9): Balanced throughput and latency.
  • ZGC / Shenandoah: Ultra-low pause times, ideal for large heaps.
  • Parallel GC: Best for batch jobs with high CPU throughput.

Reduce Object Churn

  • Reuse objects and buffers
  • Use primitive collections (eg. TIntArrayList) to reduce boxing.
  • Avoid temporary object floods (e.g., string concatenation inside loops).

Profile and Analyze Regularly

  • Use memory profiles (JMC, Eclipse MAT) to spot leaks.
  • Investigate any rising heap baselines early.

Example: Diagnosing a Leak via GC Pattern

  1. Heap baseline keeps rising every hour.
  2. GC logs show increasing "used after GC" values.
  3. Heap dump analysis reveals a large ConcurrentHashMap holding cached objects with no eviction policy.
  4. Fix -> Add cache expiration -> GC returns to steady saw-tooth-pattern.

Conclusion

Health garbage collection isn't about minimizing GC activity. It's about maintaining a predictable, balanced cycle where memory is reclaimed efficiently and the application spends most time doing real work.

When GC becomes erratic, too frequent, or too ineffective, it's a sign to:

  • Reassess heap sizing and GC algorithm choice.
  • Analyze object allocation patterns.
  • Fix leaks and optimize caching.

With consistent monitoring and tuning, we can keep the JVM's "heartbeat" steady - ensuring high throughput and long-term stability.

Further Reading

---
title: Healthy vs Non-Healthy Garbage Collection Behavior In The JVM
description: What defines healthy versus unhealthy GC behavior, how to interpret heap usage patterns, and how to correct GC issues before they impact performance?
date: 2025-10-28
keywords: [java,jvm]
---