Diagnosing and Fixing Java OutOfMemoryError: Heap Space – A Practical Guide
When Java throws OutOfMemoryError: Java heap space, this guide walks you through a diagnostic workflow that maps symptoms to causes, applies fixes, and tells you when to ask for help.
05 Sept 2025, 05:37 UTC

Problem Statement
When a Java application throws java.lang.OutOfMemoryError: Java heap space, the JVM has exhausted the heap region that is allocated for object allocation. This error stops the application in the middle of an operation, making it critical to diagnose quickly. The goal of this guide is to give you a repeatable, diagnostic‑first workflow that maps observed symptoms to concrete causes, applies targeted fixes, and tells you when to ask for help.
Short Cause/Diagnostic Table
| Cause | Typical Symptom | Quick Check |
|---|---|---|
| Memory leak | Heap usage climbs steadily, GC logs show no reclaim | jcmd VM.native_memory summary |
| Large data structures | Heap usage spikes after a single operation | Profile memory before/after operation |
| Insufficient heap size | Frequent GC pauses, error after startup | Check -Xmx setting and GC logs |
| Excessive string concatenation | Large number of short‑lived strings in a loop | Search code for “+” in loops |
| Unbounded caching | Cache grows indefinitely, no eviction | Inspect cache implementation for size limits |
Step‑by‑Step Diagnostic Workflow
Collect Baseline Heap Metrics
Run the application with GC logging enabled:
java -Xmx512m -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar myapp.jarVerify the initial heap size:
jcmd VM.native_memory summaryCheck that the
MaxHeapSizematches the-Xmxvalue.Reproduce the OutOfMemoryError
Trigger the workload that causes the crash. Immediately after the error, generate a heap dump:
jcmd GC.heap_dump /tmp/heapdump.hprofBe aware that the dump can be several gigabytes; ensure you have enough disk space.
Analyze the Dump
Open the dump in Eclipse MAT or VisualVM. Look for the “Largest Objects” tab and the “Top Retained Size” list. Pay special attention to:
- Static collections holding many entries.
- Singleton caches without eviction.
- Large arrays or collections created during a single operation.
Correlate with GC Logs
Search the GC logs for patterns such as:
- “Full GC” occurring frequently with little heap reclaimed.
- “Pause” times exceeding the threshold you care about.
- “Heap usage before GC” remaining high after a GC.
Use the
-XX:+PrintGCApplicationStoppedTimeflag to see how long the application is stopped during GC.Targeted Fixes
Based on the findings, apply one of the following:
- Memory Leak: Identify the leaking object type and remove the reference. For example, if a static
Map<String, Object>keeps entries, add a proper eviction policy or clear the map when no longer needed. - Large Data Structure: Stream data instead of loading it entirely. Example: replace
withList<String> lines = Files.readAllLines(path);Files.lines(path).forEach(this::processLine); - Insufficient Heap: Increase
-Xmxafter confirming the application legitimately needs more memory. Avoid simply bumping the value without analysis. - String Concatenation: Replace concatenation in loops with a
StringBuilderorStringJoiner.StringBuilder sb = new StringBuilder(); for (String part : parts) sb.append(part); - Unbounded Cache: Introduce a size limit or an eviction strategy (e.g., LRU via
LinkedHashMapor Guava Cache).
- Memory Leak: Identify the leaking object type and remove the reference. For example, if a static
Re‑Validate After Fix
Repeat steps 1–4. The heap usage should plateau, GC pauses should drop, and the error should no longer occur. Verify that the heap dump no longer shows the problematic retention patterns.
Escalation Criteria
If after applying the above fixes the error persists:
- Run a full heap analysis with the MAT “Leak Suspects” report.
- Enable
-XX:+HeapDumpOnOutOfMemoryErrorand analyze the dump with a commercial profiler (e.g., YourKit). - Consider increasing the heap again only after confirming that the usage is still legitimate.
- If the issue appears in a third‑party library, file a bug with the maintainers and provide the heap dump.
Concrete Example: CSV Loading Leak
Suppose a service reads a CSV file into a list and keeps the list in a static field:
public class CsvCache {
private static final List<String> rows = new ArrayList<>();
public static void load(Path file) throws IOException {
rows.clear();
rows.addAll(Files.readAllLines(file));
}
}
Each call to load adds a new ArrayList instance to the static field, and the old instance is never garbage‑collected because the static reference remains. The heap grows with each load until an OOM occurs. Fix: use a bounded cache or remove the static reference after use.
Limitations & Practical Checks
- Heap dumps can be large; ensure sufficient disk space and use
-XX:+UseCompressedOopsif possible to reduce size. - Increasing
-Xmxmay mask a leak; always confirm with a heap analysis first. - GC log parsing can be noisy; use tools like GCViewer or GCeasy for easier interpretation.
- Some leaks are only visible at high load; reproduce with realistic traffic when possible.
Wrap‑Up
By following a structured diagnostic path—collect metrics, reproduce, analyze, target, validate, and only then consider escalation—you turn the opaque OutOfMemoryError into a clear, actionable problem. Keep the heap small, the GC healthy, and the code clean, and the error will become a thing of the past.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.