Fix Java OutOfMemoryError: Java heap space
This error occurs when the Java heap reaches its maximum limit. Increase heap size with -Xmx or optimize memory usage to resolve it.
Symptoms
The application crashes with the following error in logs or console output:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Other symptoms include sudden application termination, unresponsive UI, or degraded performance before the crash. In web applications, users may see HTTP 500 errors or timeouts.
Root Causes
The Java heap is the memory area where objects are allocated during runtime. This error occurs when the JVM cannot allocate an object because the heap has reached its maximum size and garbage collection (GC) cannot free enough space. Common causes:
- Insufficient heap size: The default heap is often too small for large datasets or high-traffic applications.
- Memory leak: Objects are unintentionally retained (e.g., unclosed resources, static collections, listeners) preventing GC from reclaiming memory.
- Inefficient data structures: Using large arrays, maps, or collections without capacity planning.
- Improper configuration: Running multiple JVMs on the same host without adjusting heap limits.
Step-by-step Fix
1. Increase the Java Heap Size
Set the maximum heap size using the -Xmx JVM argument. For example, to allocate 4 GB:
java -Xmx4g -jar your-application.jar
You can also set the initial heap size with -Xms (e.g., -Xms1g). For Tomcat, edit CATALINA_OPTS in setenv.sh (Unix) or setenv.bat (Windows):
CATALINA_OPTS="-Xms512m -Xmx4g"
2. Generate and Analyze a Heap Dump
Add the following JVM arguments to generate a heap dump when OOM occurs:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dumps
Use tools like Eclipse MAT, VisualVM, or YourKit to analyze the dump. Look for:
- Largest objects and their GC roots
- Suspiciously large collections or arrays
- Unintended object retention (e.g., ThreadLocal, static maps)
3. Review Code for Memory Leaks
Common patterns:
- Unclosed streams, connections, or sessions (use try-with-resources)
- Static collections growing indefinitely (e.g., caches without eviction)
- Listener or observer registrations never removed
- Large object graphs loaded into memory unnecessarily
4. Tune Garbage Collection
Consider using the G1GC collector for large heaps:
-XX:+UseG1GC -XX:MaxGCPauseMillis=200
Monitor GC logs with -Xlog:gc* to identify frequent full GCs or long pause times.
Alternative Fixes
- Reduce object creation: Reuse objects, use primitives where possible, and avoid unnecessary string concatenations.
- Use streaming APIs: For large files or database results, process data in chunks instead of loading everything into memory.
- Increase physical memory: If the server has available RAM, allocate more to the JVM.
- Distribute load: Use multiple JVM instances or microservices to split memory usage.
Prevention
- Monitor heap usage: Use tools like Prometheus + Grafana, JMX, or New Relic to track memory trends.
- Set appropriate heap limits: Base
-Xmxon peak usage observed during load testing. - Implement caching wisely: Use bounded caches (e.g., Guava Cache, Caffeine) with eviction policies.
- Conduct regular code reviews: Look for memory leak patterns and resource handling.
- Test with realistic data volumes: Simulate production-like memory loads during QA.
- Enable GC logging: Keep GC logs for post-mortem analysis in case of future OOM errors.
| Option | Description |
|---|---|
-Xms | Initial heap size |
-Xmx | Maximum heap size |
-XX:+HeapDumpOnOutOfMemoryError | Generate heap dump on OOM |
-XX:HeapDumpPath | Directory for heap dumps |
-Xlog:gc* | Enable GC logging (Java 9+) |
Was this solution helpful?