DEV Community

Amit Sonar
Amit Sonar

Posted on

5 JVM Heap OOM Patterns You Can Reproduce on Your Laptop

OutOfMemoryError is the 3 AM page nobody wants. I built a field guide to the five heap exhaustion patterns I keep seeing in JVM-based data pipelines — each one as a small, runnable reproduction you can trigger on your laptop, diagnose like you would at 3 AM, and then fix.

The five patterns

01. Unbounded in-memory cache — A HashMap grows with input volume. GC log shows a rising post-GC staircase. Fix: bounded cache with eviction.

02. Oversized batch — One 250 MB batch against a 64 MB heap. Dies on a cliff, not a staircase. Fix: chunked reads sized for the heap.

03. Report-builder retention — Output accumulates in memory while generating a report. Looks like 01's staircase, but the retainer is the product itself. Fix: stream output to disk incrementally.

04. ThreadLocal leak — Per-thread lists grow per task on pooled threads. The staircase is invisible in the GC log alone — you need a heap dump. Fix: remove() in finally.

05. Leaked connections — A static registry pins every unclosed resource. 1:1 growth with work done. Fix: try-with-resources + deregistration.

Try it


git clone https://github.com/amits710/jvm-oom-field-guide
cd jvm-oom-field-guide
./run.sh scenario-01-unbounded-cache broken   # watch it die
./run.sh scenario-01-unbounded-cache fixed     # watch it survive

Enter fullscreen mode Exit fullscreen mode

Pure Java, zero dependencies, JDK 11+. Each scenario runs in under a minute.

What's inside each scenario

  • broken/ — minimal program that reliably OOMs
  • diagnosis.md — GC log signature, heap-dump clues, triage checklist
  • fixed/ — the corrected version: same workload, no OOM, with a COMPLETED marker so you can verify it did the same work

The full test suite (./test.sh) asserts broken runs OOM and fixed runs complete, across JDK 11/17/21/25 in CI.

Why synthetic examples?

These are teaching labs, not production code. The failure shapes — staircase vs. cliff, what's visible in GC logs vs. what needs a heap dump — are what transfer to real incidents. The code is written from scratch so you can run it without any setup.

Repo: https://github.com/amits710/jvm-oom-field-guide

Happy to answer questions about the GC signatures or diagnosis approach.

Top comments (0)