The java.lang.OutOfMemoryError is one of the most dreaded runtime errors in Java. It indicates that the Java Virtual Machine (JVM) cannot allocate an object because it has run out of memory, and the Garbage Collector cannot reclaim enough space.
However, simply increasing the Heap Size (-Xmx) is not always the solution.
In fact, there are 9 distinct types of OutOfMemoryErrors Exceptions, each with its own root cause ranging from Heap exhaustion and Metaspace limits to Native Thread issues and Container (Docker) restrictions. To fix the crash permanently, you must first identify which type you are facing. This guide covers every scenario, complete with causes and solutions.
To better understand OutOfMemoryError Exception, we first need to understand different JVM Memory regions. Here is a video clip that gives a good introduction about different JVM memory regions. But in nutshell, JVM has following memory regions:
- Young Generation: Newly created application objects are stored in this region.
- Old Generation: Application objects that are living for longer duration are promoted from the Young Generation to the Old Generation. Basically, this region holds long-lived objects.
- Metaspace: Class definitions, method definitions and other metadata that are required to execute your program are stored in the Metaspace region. This region was added in Java 8. Before that metadata definitions were stored in the PermGen. Since Java 8, PermGen was replaced by Metaspace.
- Threads: Each application thread requires a thread stack. Space allocated for thread stacks, which contain method call information and local variables are stored in this region.
- Code Cache: Memory areas where compiled native code (machine code) of methods is stored for efficient execution are stored in this region.
- Direct Buffer: ByteBuffer objects are used by modern framework (i.e. Spring WebClient) for efficient I/O operations. They are stored in this region.
- GC (Garbage Collection): Memory required for automatic garbage collection to work is stored in this region.
- JNI (Java Native Interface): Memory for interacting with native libraries and code written in other languages are stored in this region.
- misc: There are areas specific to certain JVM implementations or configurations, such as the internal JVM structures or reserved memory spaces, they are classified as ‘misc’ regions.
Types of OutOfMemoryErrors
1. OutOfMemoryError: Java Heap Space
When more objects are created in the ‘Heap’ (i.e. Young and Old) region than the allocated memory limit (i.e., ‘-Xmx’), then JVM will throw ‘java.lang.OutOfMemoryError: Java heap space’.
Below is the program that can simulate ‘java.lang.OutOfMemoryError: Java heap space’ when executed.
public class MapManager { private static HashMap<Object, Object> myMap = new HashMap<>(); public void grow() { long counter = 0; while (true) { if (counter % 1000 == 0) { System.out.println("Inserted 1000 Records to map!"); } myMap.put("key" + counter, "Large stringgggggggggggggggggggggggg" + counter); ++counter; } }}
The above program has a ‘MapManager’ class that internally contains a ‘HashMap’ object that is assigned to the ‘myMap’ variable. With in the ‘grow()’ method, there is an infinite ‘while (true)’ loop that keeps populating the ‘HashMap’ object. On every iteration, a new key and value (i.e., ‘key-0’ and ‘Large stringgggggggggggggggggggggggg-0’) is added to the ‘HashMap’. Since it’s an infinite loop, ‘myMap’ object will get continuously populated until heap capacity is saturated. Once the heap capacity limit is exceeded, application will result in ‘java.lang.OutOfMemoryError: Java heap space’.
What are the Common Causes of “Java Heap Space”?
This error is triggered by the JVM under following circumstances:
- Increase in Traffic Volume: When there is a spike in the traffic volume, more objects will be created in the memory. When more objects are created than the allocated Memory limit, JVM will throw ‘OutOfMemoryError: Java heap space’.
- Memory Leak due to Buggy Code: Due to the bug in the code, application can inadvertently retain references to objects that are no longer needed, it can lead to buildup of unused objects in memory, eventually exhausting the available heap space, resulting in OutOfMemoryError.
What are the Solutions for “Java Heap Space”?
Following are the potential solutions to fix Java Heap Space error:
- Fix Memory Leak: Analyze memory leaks or inefficient memory usage patterns using the approach given in this post. Ensure that objects are properly dereferenced when they are no longer needed to allow them to be garbage collected.
- Increase Heap Size: If OutOfMemoryError surfaced due the increase in the traffic volume, then increase the JVM heap size (-Xmx) to allocate more memory to the JVM. However, be cautious not to allocate too much memory, as it can lead to longer garbage collection pauses and potential performance issues.
2. OutOfMemoryError: GC Overhead Limit Exceeded
When Java process is spending more than 98% of its time doing garbage collection and recovering less than 2% of the heap and has been doing so far the last 5 (compile time constant) consecutive garbage collections then ‘java.lang.OutOfMemoryError: GC overhead limit exceeded’ gets thrown.
NOTE: When your application runs out of heap memory, the JVM may throw either ‘java.lang.OutOfMemoryError: Java heap space’ or ‘java.lang.OutOfMemoryError: GC overhead limit exceeded’. Although the messages differ, both indicate the same underlying issue i.e., the Java heap has been fully saturated and cannot accommodate further allocations.
In practice, these two errors are often raised interchangeably depending on how the JVM detects the condition. However, an important point to remember here is that the troubleshooting process does not change, whether you see “heap space” or “GC overhead limit exceeded,” the artifacts you need to capture, the diagnosis approach you should follow, and the resolution strategies remain exactly the same.
What are the Common Causes of “java.lang.OutOfMemoryError: GC overhead limit exceeded”?
This error is triggered by the JVM under following circumstances:
- Increase in Traffic Volume: When there is a spike in the traffic volume, more objects will be created in the memory. When more objects are created than the allocated Memory limit, JVM will throw ‘OutOfMemoryError: GC overhead limit exceeded’.
- Memory Leak due to Buggy Code: Due to the bug in the code, application can inadvertently retain references to objects that are no longer needed, it can lead to buildup of unused objects in memory, eventually exhausting the available heap space, resulting in OutOfMemoryError.
What are the Solutions for “java.lang.OutOfMemoryError: GC overhead limit exceeded”?
Following are the potential solutions to fix GC overhead limit exceeded error:
- Fix Memory Leak: Analyze memory leaks or inefficient memory usage patterns using the approach given in this post. Ensure that objects are properly dereferenced when they are no longer needed to allow them to be garbage collected.
- Increase Heap Size: If OutOfMemoryError surfaced due the increase in the traffic volume, then increase the JVM heap size (-Xmx) to allocate more memory to the JVM. However, be cautious not to allocate too much memory, as it can lead to longer garbage collection pauses and potential performance issues.
3. OutOfMemoryError: Requested Array Size
‘java.lang.OutOfMemoryError: Requested array size exceeds VM limit’ occurs when your application attempts to create an array that exceeds the maximum allowable size imposed by the JVM, which is Integer.MAX_VALUE (2,147,483,647). Even if you have sufficient heap memory available, this error will still be thrown if you try to create an array more than the imposed size limit.
Below is the program that attempts to create a very large integer array, which exceeds the VM limit:
public class OOMRequestedArraySizeExceedsVMLimit { public static void main(String[] args) { // Attempt to create an array of the size (which will exceed VM limit) int[] arr = new int[Integer.MAX_VALUE]; }}
In the above program ‘OOMRequestedArraySizeExceedsVMLimit‘ class’s ‘main()’ method tries to create a very large ‘int’ array (i.e., new int[Integer.MAX_VALUE]). When this program is executed, you will see the ‘java.lang.OutOfMemoryError: Requested array size exceeds VM limit’ reported in the console.
What causes “java.lang.OutOfMemoryError: Requested array size exceeds VM limit”?
JVM throws ‘OutOfMemoryError: Requested array size exceeds VM limit’ under the following conditions:
- Parsing/Loading Large Files: Trying to load or parse very large files (e.g., reading an entire file into a byte array) without chunking can push array size beyond the safe limits.
- Data Structure Pre-Allocation: Some frameworks or poorly written utilities may try to pre-allocate massive arrays assuming they will be used to store large datasets in-memory, which may not be practical.
- Incorrect Calculations for Array Size: A bug or miscalculation in the code, such as multiplying large values, can cause the array size to exceed the valid integer range.
What are the Solutions for ‘OutOfMemoryError: Requested array size exceeds VM limit’?
Following are the potential solutions to fix Requested array size exceeds VM limit error:
- Increase Heap Size: You can increase the maximum heap size (-Xmx) when running your Java application. This allows more memory to be allocated to your application, potentially allowing larger arrays to be created. However, be cautious as increasing heap size may have performance implications and may not always be a feasible solution, especially in memory-constrained environments.
- Reduce array size: Try to see whether you can reduce the array size. If creating such a large array is unavoidable, consider alternative approaches such as using different data structures or processing data in smaller chunks.
4. OutOfMemoryError: Metaspace
When lot of class definitions, method definitions are created in the ‘Metaspace’ region than the allocated Metaspace memory limit (i.e., ‘-XX:MaxMetaspaceSize’), JVM will throw ‘java.lang.OutOfMemoryError: Metaspace’.
Below is the java program that simulates ‘java.lang.OutOfMemoryError: Metaspace’ when executed.
import java.util.UUID;import javassist.ClassPool;public class OOMMetaspace { public static void main(String[] args) throws Exception { ClassPool classPool = ClassPool.getDefault(); while (true) { // Keep creating classes dynamically! String className = "com.buggyapp.MetaspaceObject" + UUID.randomUUID(); classPool.makeClass(className).toClass(); } }}
In the above program ‘OOMMetaspace’ class’s ‘main()’ method contains an infinite ‘while (true)’ loop. Within the loop, thread uses open-source library javassist to create dynamic classes whose names start with ‘com.buggyapp.MetaspaceObject’. Class names generated by this program will look something like this: ‘com.buggyapp.MetaspaceObjectb7a02000-ff51-4ef8-9433-3f16b92bba78’. When so many such dynamic classes are created, the Metaspace memory region will reach its limit and the JVM will throw ‘java.lang.OutOfMemoryError: Metaspace’.
What are the Common Causes of “java.lang.OutOfMemoryError: Metaspace”?
This error is triggered by the JVM under following circumstances:
- Creating large number of dynamic classes: If your application uses Groovy kind of scripting languages or Java Reflection to create new classes at runtime.
- Loading large number of classes: Either your application itself has a lot of classes or it uses a lot of 3rd party libraries/frameworks which have a lot of classes in it.
- Loading large number of class loaders: Your application is loading a lot of class loaders.
What are the Solutions for ‘OutOfMemoryError: Metaspace’?
Following are the potential solutions to fix Metaspace error:
- Increase Metaspace Size: If OutOfMemoryError surfaced due to increase in number of classes loaded, then increase the JVM’s Metaspace size (-XX:MetaspaceSize and -XX:MaxMetaspaceSize). This solution is sufficient to fix most of the ‘OutOfMemoryError: Metaspace’ errors, because memory leaks rarely happen in the Metaspace region.
- Fix Memory Leak: Analyze memory leaks in your application using the approach given in this post. Ensure that class definitions are properly dereferenced when they are no longer needed to allow them to be garbage collected.
5. OutOfMemoryError: Permgen Space
When lot of class definitions, method definitions are created in the ‘Permgen space’ region than the allocated Permgen memory limit (i.e., ‘-XX:PermSize’), JVM will throw ‘java.lang.OutOfMemoryError: Permgen space’.
Below is the Java program that simulates ‘java.lang.OutOfMemoryError: Permgen space’ when executed.
import java.util.UUID;import javassist.ClassPool;public class OOMPermgen { public static void main(String[] args) throws Exception { ClassPool classPool = ClassPool.getDefault(); while (true) { // Keep creating classes dynamically! String className = "com.buggyapp.PermgenObject" + UUID.randomUUID(); classPool.makeClass(className).toClass(); } }}
In the above program ‘OOMPermgen’ class’s ‘main()’ method contains an infinite ‘while (true)’ loop. Within the loop, thread uses open-source library javassistt to create dynamic classes whose names start with ‘com.buggyapp.PermgenObject’. Class names generated by this program will look something like this: ‘com.buggyapp.PermgenObjectb7a02000-ff51-4ef8-9433-3f16b92bba78’. When so many such dynamic classes are created, Permgen memory region will reach its limit and JVM will throw ‘java.lang.OutOfMemoryError: Permgen space’.
What are the Common Causes of “java.lang.OutOfMemoryError: Permgen space”?
This error is triggered by the JVM under following circumstances:
- Creating large number of dynamic classes: If your application uses Groovy kind of scripting languages or Java Reflection to create new classes at runtime.
- Loading large number of classes: Either your application itself has a lot of classes or it uses a lot of 3rd party libraries/frameworks which have a lot of classes in it.
- Loading large number of class loaders: Your application is loading a lot of class loaders.
What are the Solutions for ‘OutOfMemoryError: Permgen space’?
Following are the potential solutions to fix Permgen space error:
- Increase Permgen Size: If OutOfMemoryError surfaced due to increase in number of classes loaded, then increase the JVM’s Permgen size (-XX:PermSize). This solution is sufficient to fix most of the ‘OutOfMemoryError: Permgen space’ errors, because memory leaks rarely happen in the Permgen region.
- Fix Memory Leak: Analyze memory leaks in your application using the approach given in this post. Ensure that class definitions are properly dereferenced when they are no longer needed to allow them to be garbage collected.
6. OutOfMemoryError: Unable to create new native threads
When a large number of threads are created in the native memory region than the available RAM capacity, JVM will throw ‘java.lang.OutOfMemoryError: Unable to create new native threads’.
Below is the program that can simulate ‘java.lang.OutOfMemoryError: Unable to create new native threads’ when executed.
public class ThreadLeakDemo { public static void start() { while (true) { try { Thread.sleep(100); } catch (Exception e) { } new ForeverThread().start(); } }}public class ForeverThread extends Thread { @Override public void run() { try { // sleep for 2 hours Thread.sleep(120 * 60 * 1000); } catch (Exception e) {} }}
The above program has a ‘ThreadLeakDemo#start()’ method. Within the ‘start()’ method, there is an infinite ‘while (true)’ loop that keeps launching ‘ForeverThread’ every 100 milliseconds. If you notice the code of the ‘ForeverThread’, it puts the thread to sleep for 2 hours. It means the application is going to be flooded with ‘ForeverThread’ which will terminate only after 2 hours. Once all the ‘ForeverThread’ size exceeds the native memory limit, JVM will throw ‘java.lang.OutOfMemoryError: Unable to create new native threads’.
What are the Common Causes of Java’s “Unable to create new native threads” Error?
This error is triggered by the JVM under following circumstances:
- Thread Leak due to Buggy Code: Due to the bug in the code, application can inadvertently create a lot of new threads, it can lead to buildup of unused threads in memory, eventually exhausting the available native memory, resulting in OutOfMemoryError.
- Lack of RAM capacity: When there is a lack of RAM capacity in the container/device in which the application is running.
- More processes in Memory: When other processes are running on the container/device, it leaves less room for the threads to be created in the native memory.
- Kernel Limit: By default, Kernel sets a limit on the number of threads each process can create. When the application creates more threads than the allowed kernel limit.
What are the Solutions for ‘OutOfMemoryError: Unable to create new native threads’?
Following are the potential solutions to fix Unable to create new native threads error:
- Fix Thread Leak: Analyze the thread dump of your application and identify the leaking threads. Instrument fix to ensure that threads are properly terminated after it completed executing its tasks.
- Increase RAM capacity: Try to run your application on a container/device which has larger RAM capacity.
- Reduce other processes: Terminate (or move) other processes that are running on the container/device, so that there is more room for the java application to create new threads.
- Reduce thread stack size: When you reduce the thread’s stack size (by using -Xss JVM argument), your application can create a number of threads within the same amount of memory. However, be cautious when you pursue this option, as reducing thread stack size can result in StackOverflowError.
- Change Kernel setting per process thread limit: By default, Kernel sets a limit on the number of threads each process can create. If OutOfMemoryError is happening because of this limit, then you can increase this limit by using ‘limit -u’ command.
7. OutOfMemoryError: Direct buffer memory
When lot of objects are created in direct buffer region, than the allocated direct buffer memory limit, (i.e., ‘-XX:MaxDirectMemorySize’), JVM will throw ‘java.lang.OutOfMemoryError: Direct buffer memory’.
Below is the program that attempts to create a very large ByteBuffer, which exceeds the VM limit:
import java.nio.ByteBuffer;public class OOMDirectBuffer { public static void main(String[] args) { while (true) { // Allocate a large direct ByteBuffer ByteBuffer buffer = ByteBuffer.allocateDirect(Integer.MAX_VALUE); } }}
In the above program ‘OOMDirectBuffer‘ class’s ‘main()’ method tries to create a very large java nio’s ByteBuffer object (i.e., Integer.MAX_VALUE). When this program is executed, you will see the ‘java.lang.OutOfMemoryError: Direct buffer memory’ reported in the console.
What are the Common Causes of “Direct buffer memory” OutOfMemoryError in Java?
This error is triggered by the JVM under following circumstances:
- Memory Leak due to Buggy code: If your application is not properly releasing direct buffers after use, they can accumulate over time and eventually exhaust the available direct buffer memory.
- High Rate of Allocation: If your application is allocating direct buffers at a very high rate and not releasing them promptly, it can quickly consume the available memory.
- Switching from Spring RestTemplate to WebClient: Spring Boot is a popular framework for Java enterprise applications. One common method of integration with internal or external applications is through RestTemplate APIs. Modern versions of Spring advocate to use Java NIO-based WebClient for better performance. While NIO based Webclient delivers better performance, it shifts the objects creation from the heap memory region to the Direct Buffer region. Thus when you make this shift, it will result in memory pressures in the Direct Buffer region.
What are the Solutions for ‘OutOfMemoryError: Direct buffer memory’?
Following are the potential solutions to fix Direct buffer memory error:
- Fix Memory Leak: Analyze memory leak in the Direct Buffer memory region, ensure that objects are properly dereferenced when they are no longer needed to allow them to be garbage collected.
- Increase Direct Buffer size: If OutOfMemoryError surfaced due the increase in the traffic volume, then increase the JVM’s Direct Buffer Memory region size (-XX:MaxDirectMemorySize).
- Upgrade to Java 17 (or above version): Enhancements have been made in Java 17 to use the Direct Buffer Memory region in an effective manner. Thus, if you happen to be running on a version less than Java 17, upgrade it. Here is a case study that showcases the performance optimization to Direct Buffer Memory region in Java 17.
8. OutOfMemoryError: Kill Process or Sacrifice Child
When there is a lack of RAM capacity in the container/device, the kernel will terminate the memory consuming processes to free up the RAM. If that terminated process turns out to be a Java application, it will result in ‘java.lang.OutOfMemoryError: Kill process (java) or sacrifice child’.
What are the Common Causes of “java.lang.OutOfMemoryError: Kill process or sacrifice child”?
This error is triggered by the JVM under following circumstances:
- More processes in the device: When a lot of other processes are running on the container/device, it leaves less memory for the Java application to run.
- Initial and Max Heap size set to different values: If initial heap size (i.e., -Xms) is configured at a lower value than the max heap size (i.e., -Xmx), then during runtime, Java application’s memory size will grow. If there is a lack of RAM capacity during that growth time, the kernel will terminate the Java application throwing this error.
- Native Memory region growing: In case the initial and max heap size is set to the same value, native memory region of the JVM can grow during the runtime. If native memory is growing and there is a lack of RAM capacity, then the kernel can terminate the Java application by throwing this error.
What are the Solutions for ‘OutOfMemoryError: Kill process (java) or sacrifice child’?
Following are the potential solutions to fix Kill process (java) or sacrifice child error:
- Increase RAM capacity: Try to run your application on a container/device which has larger RAM capacity.
- Reduce other processes: Terminate (or move) other processes that are running on the container/device, so that there is enough memory for the Java application.
- Set initial Heap and Max Heap to same value: When you set the initial heap size (i.e. -Xms) and max heap size (-Xmx) to the same value, JVM will be allocated with maximum heap size right at the startup time. Thus, JVM’s memory allocation will not grow or shrink at runtime. Kernel typically terminates the application which is constantly demanding more memory. Thus, the kernel will not terminate the Java application in the middle.
- Fix Leak in Native Memory: Sometimes there could be a leak in the Native Memory as well. There could be a thread leak, or direct buffer leak – which can cause increased memory consumption. Instrument proper fix to arrest those leaks.
9. OutOfMemoryError: reason stack_trace_with_native_method
‘OutOfMemoryError: stack_trace_with_native_error_method’ happens when the Java Virtual Machine (JVM) encounters a situation where it’s unable to allocate sufficient memory for the execution stack of a thread containing native method invocations.
NOTE: ‘java.lang.OutOfMemoryError: stack_trace_with_native_error_method’ occurs only if your application is using JNI (Java Native Interface) and connecting the native applications. Most applications don’t use JNI.
What are the Common Causes of “OutOfMemoryError: reason stack_trace_with_native_method”?
This error is triggered by the JVM under following circumstances:
- Heavy Usage of Native Methods: Native methods are functions implemented in languages other than Java, such as C or C++. Excessive usage of native methods can lead to increased memory consumption and stack overflow issues.
- Recursive Native Method Calls: Recursive calls to native methods can result in a rapidly growing call stack, eventually exhausting the available stack memory allocated to the thread.
What are the Solutions for ‘OutOfMemoryError: reason stack_trace_with_native_method’?
Following are the potential solutions to fix reason stack_trace_with_native_method error:
- Analyze Stack Traces: Examine the stack traces provided in the error logs to identify the sequence of native method invocations leading to the error. This can help pinpoint the source of the problem and guide troubleshooting efforts.
- OS native tools: You might need to use following Operative System native tools to diagnose the issue:
- a) DTrace: A powerful dynamic tracing framework available on certain Unix-like operating systems (e.g., macOS, FreeBSD). DTrace allows you to observe system behavior in real-time, making it useful for analyzing performance and diagnosing memory issues.
- b) pmap: This command-line utility provides detailed information about the memory mappings of a process, including memory usage and allocation. By examining the memory map of a Java process, you can identify memory-intensive areas and potential memory leaks.
- c) pstack: Used for printing the call stack of a running process, pstack can help identify the sequence of function calls leading to stack overflow errors caused by recursive native method invocations. Analyzing the call stack can reveal patterns or bottlenecks that contribute to memory exhaustion.
Conclusion
Understanding the different types of OutOfMemoryErrors (OOME) in Java is essential for diagnosing and resolving memory issues effectively. Each type of OOME points to a specific area of concern within your application, from heap space limitations to GC overhead, and more. By familiarizing yourself with these errors, you can better anticipate potential problems and implement preventive measures to ensure your applications run smoothly.
To recap, we have explored the nine types of OOME in Java, drawing parallels to the nine planets in our solar system. With this knowledge, you are now better equipped to handle memory-related issues and maintain the stability and performance of your Java applications.
Here’s the deck for you to revisit the topics covered. Access the presentation deck below to review the key takeaways and strategies discussed:
FAQ
145 thoughts on “Java OutOfMemoryError Exception: Understanding 9 Types, Causes & Solutions”
Add yours
-
If I’m running a small Java application, what’s a safe default heap size to start with, and how do I decide when to increase it?
-
If JVM is killed by the OS with OOMKilled (no stack trace), how we can confirm whether it was a heap issue, native memory issue, or container memory limit?
-
For Requested array size exceeds VM limit, how can we identify whether it’s caused by parsing large files or by faulty array size calculations?
-
Can Garbage Collector tuning alone prevent OOM error, or we always need application-level fixes?
-
Which OutOfMemoryError would be the most common one when we’re using container runtimes like Docker or Kubernetes?
-
This is one of the good articles I have ever read in JVM space.
I have one question related to OOM error related to direct buffer memory
Which version of Spring is demonstrating this issue?

Share your Thoughts!Cancel reply