← Debugging Guides

阅读中文版本

Java — OutOfMemoryError: Java heap space

Diagnose a Java heap exhaustion with heap dumps, GC logs, and allocation analysis, and fix the leak or sizing instead of only raising -Xmx.

advanceddebuggingjavamemory

Symptoms

  • java.lang.OutOfMemoryError: Java heap space
  • The JVM becomes unresponsive or exits after a period of high load
  • Full GC runs frequently and reclaims little memory
  • The failure repeats after a restart, often at a similar time or request count

Possible causes

  • A collection or cache grows without eviction
  • A request loads too much data into memory
  • A leak from listeners, ThreadLocals, or classloaders
  • The heap is genuinely too small for the live set
  • A container memory limit kills the JVM before the heap limit is reached

Diagnosis steps

Capture a heap dump on the failure

java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp -Xmx512m -jar app.jar

Interpretation

The dump records live objects at exhaustion. Analyze dominators and retained sizes in Eclipse MAT or VisualVM.

Inspect GC behavior

java -Xlog:gc*:file=gc.log -jar app.jar

Interpretation

Frequent full GCs with little reclaimed memory indicate a live-set leak; a large live set after GC may mean undersizing.

Count objects and threads in a running JVM

jcmd PID GC.heap_info && jmap -histo:live PID | head -30

Interpretation

The histogram shows which classes dominate. A growing count of domain objects points to a leak.

Root cause

The Java heap could not satisfy an allocation because live objects exceeded the heap. The cause is either a leak or an undersized heap for the actual live set.

Fix

Fix unbounded caches, queries, and listeners; release references; stream large data. Raise -Xmx only after measuring the live set and confirming the container limit has headroom. Match the container memory limit to the heap plus metaspace and native overhead.

Risk note

Raising -Xmx without fixing a leak delays the failure and may trigger the container OOM killer, losing the heap dump and making diagnosis harder.

Verify the fix

Run the same workload longer than the original failure window with heap dumps enabled and GC logging. Confirm the live set plateaus, old-gen usage stabilizes after GC, and the container memory stays below its limit.

A heap error is a symptom

OutOfMemoryError: Java heap space means the allocation failed, not that the heap setting is wrong. The live set may be leaking or legitimately larger than the configured maximum. Start with a heap dump and GC logs; guessing at -Xmx wastes time and may hide the cause.

java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp -Xmx512m -jar app.jar

Leak or undersizing

If full GCs repeatedly reclaim little and the old generation stays high, live objects are growing. Use the heap dump to find the dominator tree and the retainer path. If the live set is stable and close to the maximum, the heap may be undersized; measure the post-GC live set before increasing it.

Container limits

A JVM in a container must account for heap, metaspace, code cache, thread stacks, and native memory. A 512 MB container with -Xmx512m leaves nothing for the rest and gets OOM-killed. Set the container limit above the total JVM footprint and leave headroom.

Verify the plateau

Run a load test longer than the original failure window, with dumps and GC logs enabled. A fixed leak shows a plateau after the fix; an undersized heap stays close to the new limit but does not climb indefinitely. Check container memory, not only heap.