Overview
Many of us came across famous
What is a memory leak?
Every application needs to store data such as variables and objects temporarily. As we already know, applications running on JVM depends on it to provide sufficient memory. However, JVM’s memory is also limited and largely depends on the underlying memory of OS. Hence, it is important for applications running on JVM to manage their memory properly. Applications are expected to release the memory resources after their use, but if an application does not release the memory then that application has memory leak, which eventually crashes with the
This is the most common performance-related error you can find. You see this error when JVM runs out of allocated memory and cannot allocate more objects. There are various ways by which you can get into this situation. Let’s explore them one by one.

1. java.lang.OutOfMemoryError: Java heap space
Java heap space is created, when the application loads up. If for some reason your application is not making old unused objects available to the garbage collector, all these objects are going to consume this limited available space leaving no space for new objects. Hence, when a new object creation request comes in, JVM throws the OutOfMemoryError.
Also, in a typical web application scenario, if your application’s traffic increases dramatically, it is going to consume all the available memory to serve these flooded requests. Hence, there will be a time when there won’t be any memory available to support new requests and your application may crash for the OutOfMemoryError.
Refer to the following example, which generates the OutOfMemoryError: Java heap space error exception:
Example :
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package com.codenuclear; public class OutOfMemoryError { public static void main(String args[]) { OutOfMemoryError ome = new OutOfMemoryError(); ome.generateMyIntArray(1,50); } public void generateMyIntArray(int start, int end){ int multiplier = 100; for(int i = 1; i < end; i++) { System.out.println("Round " + i + " Free Memory: " + Runtime.getRuntime().freeMemory()); int[] myIntList = new int[multiplier]; for(int j= i; j > 1; j--){ myIntList[j] = i; } multiplier = multiplier * 10; } } } |
Output :
2. java.lang.OutOfMemoryError: GC Overhead limit exceeded
This is a rather rare form of the exception OutOfMemoryError. As the name suggests, this error occurs when garbage collector has reached its overhead limit. This means, it is running all the time, but is very slow in collecting objects. See the following example;
Example :
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
package com.codenuclear; import java.util.Map; import java.util.Random; public class GCOverheadTest { public static void main(String args[]) throws Exception { Map<Object,Object> map = System.getProperties(); Random r = new Random(); while (true) { map.put(r.nextInt(), "GC Overhead Limit Test"); } } } |
To replicate the issue, Let’s execute above program with low memory resources with parallel GC. Run program with
java -Xmx100m -XX:+UseParallelGC GCOverheadTest
Output :
In order to improve the garbage collector’s performance, the JVM is configured to detect whether during the garbage collection process, by default, the Java process recovers less than 2 percent of the heap by spending more than 98 percent of its processing time. When this happens, it throws the GC overhead limit exceeded error. This check is necessary because if GC is only going to recover 2 percent of the memory, there won’t be much space for new objects. Hence, the JVM is going to run the GC process again and again only to claim this tiny space. This activity is going to utilize CPU resources fully and application will not respond to user requests anymore. Hence, this check is necessary. However, We can turn off this check by adding the
3. java.lang.OutOfMemoryError: Permgen space
Java memory is divided into various regions. As we have seen in the figure. When JVM first initialized, it set the sizes of all these regions to platform-specific defaults. We can also specify the sizes in the VM parameter section, which will be used for the allocation over the platform-specific defaults. The preceding error is related to permanent generation area, which means the size of the permanent generation area in the memory is filled up. Permanent generation mostly stores the declarations, including name and fields of the class, methods with their bytecode, object arrays, constant pool information, and JIT compiler optimization of the loaded classes. This states that the permanent generation space is mainly affected by the number of classes and the size of each class. It means that a very big class or large number of classes are going to contribute to this type of error,
This is applicable to JVM 7 and earlier. Java 8 has changed the memory model.
4. java.lang.OutOfMemoryError: Metaspace
Metaspace is the replacement of the permanent generation region in Java 8, the Metaspace region now stores the information of permanent generation. It is used to store things like the declarations, including name and fields of the class, methods with their bytecode, object arrays, constant pool information and JIT compiler optimization of the loaded classes.
Metaspace can be initialized with param
java -XX:MaxMetaspaceSize=1m MetaspaceTest
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
package com.codenuclear; public class MetaspaceTest { public static void main(String[] args) { while (true) { new Metaspace(); } } } class Metaspace{ } |
In the previous program, the while loop runs without any limit and generates classes at the runtime. These classes definitions then consume Metaspace and eventually throw the OutOfMemoryError: Metaspace exception. See the following output:
Output :
5. java.lang.OutOfMemoryError: Unable to create new native thread
As we already know, Java supports multithreading, We can create as many threads as we like till we consume all the available memory for the JVM. Once the memory limit is reached, JVM native code can no longer create a new native thread from the underlying operating system
Example :
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
package com.codenuclear; public class NativeThreadTest { public static void main(String[] args) { while (true) { NativeThread nativeThreadObj=new NativeThread(); nativeThreadObj.start(); } } } class NativeThread extends Thread { public void run() { try { Thread.sleep(10000000); } catch(InterruptedException e) { } } } |
As mentioned earlier, the precceding program is going to throw java.lang.OutOfMemoryError: unable to create new native thread. Please note that the native thread limit is platform-dependent so it will take a different number of threads in order to reach to the limit.
6. java.lang.OutOfMemoryError: request size bytes for reason
This error occurs when the swap memory space is also fully consumed by application. Every time we start our application, JVM allocates the appropriate amount of memory to all the regions depending on our VM parameter. This means, our application has an upper limit for the memory it can use. Hence, if our application happens to request more memory than the allocated limit, the operating system uses the swap space from the hard drive as a virtual memory.
7. java.lang.OutOfMemoryError: Requested array size exceeds VM limit
As everything with the JVM memory regions, there is a limit on the number of array size that the program can allocate. This limit is platform specific. If our application uses an array size more than the allowed size for the underlying platform, we will see this error. The following code will help you understand this error:
0 1 2 3 4 5 6 7 8 9 |
package com.codenuclear; public class ArraySizeLimitTest { public static void main(String[] args){ int[] intArray = new int[Integer.MAX_VALUE-1]; } } |
If We run the preceding program, it is going to throw the desired error as the int primitives that we are trying to generate requires more memory than the defaults allocated by the JVM.