Skip to content
Latchkey

Java "OutOfMemoryError: GC overhead limit exceeded" in CI

GC overhead limit exceeded is a heap-pressure signal: the JVM spent over 98% of recent time in garbage collection while recovering under 2% of the heap. It is effectively thrashing - almost out of memory but not yet fully exhausted.

What this error means

A build or test fails with java.lang.OutOfMemoryError: GC overhead limit exceeded. It often follows a long slowdown as GC churns, on memory-heavy compilation, annotation processing, or large test fixtures.

java
java.lang.OutOfMemoryError: GC overhead limit exceeded
        at java.base/java.util.Arrays.copyOf(Arrays.java:3537)
        at com.example.Loader.readAll(Loader.java:44)

Common causes

Heap too small for the workload

The configured -Xmx is too low for the build/test's live data; the collector keeps running but cannot free enough, so it gives up.

Excessive allocation or a leak

Loading huge files into memory, unbounded caches, or accumulating fixtures inflates live data until GC cannot keep pace.

How to fix it

Raise heap for the build/test JVM

Increase -Xmx within the runner's limits for the right tool.

.github/workflows/ci.yml
# Maven build/test JVM:
env:
  MAVEN_OPTS: -Xmx2g
# Gradle test workers:
# test { maxHeapSize = '2g' }

Reduce allocation pressure

  1. Stream large inputs instead of reading them fully into memory.
  2. Bound caches and clear large test fixtures between cases.
  3. If the heap is genuinely sufficient, capture a heap dump (-XX:+HeapDumpOnOutOfMemoryError) to find a leak.

How to prevent it

  • Set realistic -Xmx for build and test JVMs, stream large data, and bound caches so the collector is not perpetually thrashing.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →