---
title: JVM G1 and ZGC Tuning on AWS Corretto for ECS and EKS
description: A heap that is too small triggers G1 humongous allocations, and one that is too large balloons pause times on Graviton. Corretto on ECS/EKS/Lambda Java, and when ZGC generational beats G1 for API heaps.
url: https://www.joinhorizon.co/blog/jvm-g1-zgc-garbage-collection-tuning-aws/
datePublished: 2026-06-12T00:00:00.000Z
dateModified: 2026-10-28T00:00:00.000Z
author: palaniappan-p
category: Cloud Architecture
tags: engineering-guide, java, performance, aws
---

# JVM G1 and ZGC Tuning on AWS Corretto for ECS and EKS

> A heap that is too small triggers G1 humongous allocations, and one that is too large balloons pause times on Graviton. Corretto on ECS/EKS/Lambda Java, and when ZGC generational beats G1 for API heaps.

As of June 2026, Amazon Corretto 21+ defaults to G1 on server classpaths. ZGC with generational mode targets sub-ms pauses on large heaps (&gt;8 GB).

## Symptoms, mechanisms, and AWS controls

| Production symptom      | Mechanism                       | AWS control                                          |
| ----------------------- | ------------------------------- | ---------------------------------------------------- |
| Periodic latency spikes | G1 evacuation pause             | Switch to ZGC generational on Corretto 21+           |
| OOM despite free heap   | Metaspace or direct buffer leak | ECS/EKS memory limits, CloudWatch Container Insights |
| GC logs missing in prod | No unified observability        | ADOT Java agent → AMP, JFR streaming on EKS          |

My recommendation: on Corretto 21+, default new latency-sensitive services to ZGC generational and keep G1 only for throughput-bound batch workloads.

> **Benchmark pattern (hypothetical workload):** Corretto 21 on ECS Fargate 4vCPU/8GB, G1 default: 180ms GC pause p99; ZGC generational (-XX:+UseZGC -XX:+ZGenerational on JDK 21; generational is the default from JDK 23): 4ms p99 pause at same heap, 6% higher CPU overhead; throughput-sensitive batch job favors G1.

## Tuning signals on AWS

| Signal             | Action                                         |
| ------------------ | ---------------------------------------------- |
| `Pause Young` high | Increase `-Xmx` or reduce allocation rate      |
| Humongous objects  | Object size &gt; 50% G1 region; fix batch sizes |
| Container OOM      | `-XX:MaxRAMPercentage=75` on ECS/EKS cgroups   |

**Lambda Java:** minimize heap. Cold start includes JVM init, so consider SnapStart (where supported) or Graal native for a latency SLO.

## AWS services map

| Need                    | Service                          | Skip when                                      |
| ----------------------- | -------------------------------- | ---------------------------------------------- |
| Low-latency JVM runtime | Corretto 21 on ECS/EKS           | Sub-millisecond C++ services                   |
| GC telemetry            | AMP + ADOT Java instrumentation  | Batch jobs with multi-minute pauses acceptable |
| Heap sizing             | Fargate task memory / EKS limits | Lambda with 128MB fixed heap                   |

## What to do this week

1. Enable GC logs to CloudWatch via sidecar or JFR snapshots on load test.
2. Match container memory limit to heap + native + metaspace headroom.
3. A/B G1 vs ZGC on same `c7g` task size with identical load.

## More in this track

Part of the **Engineering Guides** library (June 2026).

- Next: [Part 2](https://www.joinhorizon.co/blog/virtual-threads-lock-free-concurrency-high-throughput-aws/)
- Browse tracks: [Engineering Guides hub](https://www.joinhorizon.co/resources/engineering-guides/)

## What this guide doesn't cover

Virtual threads are covered in part 2 of the runtime track.

## FAQ

### When should I keep G1 instead of ZGC on Corretto 21?
Keep G1 for throughput-bound batch jobs that can absorb pauses. Default new latency-sensitive APIs on Corretto 21+ to generational ZGC. The hypothetical Fargate 4vCPU/8GB pattern in this guide dropped p99 pause from 180ms (G1) to 4ms (ZGC) at about 6% more CPU.

### Why did the container OOM with free heap?
Metaspace, direct buffers, or native headroom, not the Java heap. Set -XX:MaxRAMPercentage=75 against ECS/EKS cgroup limits and watch Container Insights. Humongous G1 objects also mean the batch size is larger than half a G1 region.

### Should I tune GC on Lambda Java the same way as ECS?
No. Minimize heap; cold start includes JVM init. Consider SnapStart where supported or Graal native for a latency SLO. Do not copy ECS -Xmx recipes into 128MB functions.

### How do I see GC in production without log-flooding CloudWatch?
ADOT Java agent into AMP, or JFR snapshots on a load test. Missing GC logs are an observability gap, not proof pauses are gone.

---

*Source: https://www.joinhorizon.co/blog/jvm-g1-zgc-garbage-collection-tuning-aws/*
