java.lang.OutOfMemoryError

Fixing Java OutOfMemoryError: Java heap space

Programming & Dev Tools Intermediate 👁 0 views 📅 May 25, 2026

This error occurs when the JVM runs out of heap memory. Increase heap size with -Xmx, optimize code, and monitor usage to prevent recurrence.

Symptoms

When a Java application runs out of heap memory, it throws java.lang.OutOfMemoryError: Java heap space. Common symptoms include:

  • Application crashes or freezes unexpectedly.
  • Error logs showing OutOfMemoryError with stack traces.
  • Slow performance followed by abrupt termination.
  • In web servers (e.g., Tomcat), requests fail with 500 errors.

Root Causes

The Java heap is where objects are allocated. The error appears when the JVM cannot allocate an object due to insufficient heap space. Primary causes include:

  • Insufficient heap size: Default heap (e.g., 256MB) is too small for the application's workload.
  • Memory leaks: Objects are unintentionally held in memory (e.g., forgotten references, static collections, listeners not removed).
  • High data volume: Processing large files, datasets, or many concurrent users without increasing heap.
  • Inefficient data structures: Using memory-heavy structures like ArrayList for huge datasets.
  • Fragmentation: Frequent allocation/deallocation of objects of different sizes can fragment the heap.

Step-by-Step Fix

1. Increase JVM Heap Size

Set the maximum heap size using the -Xmx flag. For example, to allow 2GB heap:

java -Xmx2g -jar myapp.jar

Also set initial heap (-Xms) to the same value to avoid resizing overhead:

java -Xms2g -Xmx2g -jar myapp.jar

For Tomcat, edit CATALINA_OPTS in setenv.sh or setenv.bat:

export CATALINA_OPTS="-Xms2g -Xmx2g"

For Eclipse/IntelliJ, set in run configuration VM arguments.

2. Identify Memory Leaks

Use heap dump analysis. Generate a heap dump when OOM occurs:

java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dump.hprof -Xmx2g -jar myapp.jar

Analyze with tools like Eclipse MAT or VisualVM. Look for:

  • Large object graphs held by static fields.
  • ThreadLocal variables not cleaned up.
  • Unclosed resources (streams, connections).
  • Listener/callback registrations never removed.

3. Optimize Code

  • Use appropriate data structures: prefer ArrayList over LinkedList for random access.
  • Process data in streams instead of loading everything into memory.
  • Set collection initial capacities to avoid resizing.
  • Clear references explicitly when done (e.g., list.clear()).

4. Monitor and Tune Garbage Collection

Enable GC logging:

-Xlog:gc*:file=gc.log

Analyze GC logs to see if GC is running too frequently or not reclaiming memory. Consider switching GC algorithm (e.g., G1GC for large heaps):

-XX:+UseG1GC

5. Use Profiling Tools

Run your application under load with a profiler (VisualVM, JProfiler) to identify memory-hungry methods or objects.

Alternative Fixes

  • Reduce object size: Use primitive types instead of wrapper classes, use StringBuilder instead of string concatenation.
  • Increase swap space (temporary, not recommended for production).
  • Distribute load: Use multiple JVM instances or microservices.
  • Use off-heap storage: For caches, use libraries like Ehcache or MapDB that store data outside the heap.

Prevention

  • Set appropriate heap size based on load testing.
  • Implement code reviews focusing on memory management.
  • Use static analysis tools (FindBugs, SonarQube) to detect potential leaks.
  • Monitor heap usage with JMX or APM tools (New Relic, Datadog).
  • Set up alerts for high heap usage (e.g., >80% of max).
  • Regularly review and clean up unused references.

Example: Fixing a Memory Leak

Suppose you have a cache implemented as a static HashMap that grows indefinitely. Fix by using WeakHashMap or a bounded cache (e.g., Guava Cache):

// Before: static Map cache = new HashMap<>();
// After: CacheBuilder.newBuilder().maximumSize(1000).build()

This prevents unbounded growth and avoids OOM.

Was this solution helpful?