Overview

Many of us came across famous OutOfMemoryError. This is the last thing you want to get on a production application as some companies may loose million dollars per minute in cases of server failure. We may have guessed the meaning of the OutOfMemoryError. Yes, you are right, Our application has used up all the available memory allocated to JVM. We may be thinking, since the server resources are so cheap, We can just add more RAM and this problem will go away. Well, this approach may work for a couple of days. Increasing server resources is not the answer. If we have a memory leak in our code, then no matter how much memory we add, We are going to come to the same situation soon.

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 OutOfMemoryError.

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.

Java Memory Model
Java Memory Model

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 :
Output :
Round 1 Free Memory: 254741016 Round 2 Free Memory: 254741016 Round 3 Free Memory: 254741016 Round 4 Free Memory: 254741016 Round 5 Free Memory: 254741016 Round 6 Free Memory: 250741000 Round 7 Free Memory: 210740984 Round 8 Free Memory: 210772712 Exception in thread “main” java.lang.OutOfMemoryError: Java heap space at com.codenuclear.b.OutOfMemoryError.generateMyIntArray(OutOfMemoryError.java:16) at com.codenuclear.b.OutOfMemoryError.main(OutOfMemoryError.java:8)

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 :

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 :
Exception in thread “main” java.lang.OutOfMemoryError: GC overhead limit exceeded at java.util.Hashtable.addEntry(Unknown Source) at java.util.Hashtable.put(Unknown Source) at com.codenuclear.GCOverheadTest.main(GCOverheadTest.java:10)

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 -XX:-UseGCOverheadLimit flag to the VM parameter.

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, OutOfMemoryError.

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 -XX:MaxMetaspaceSize, Let’s run below program with MaxMetaspaceSize of 1 Mb.

java -XX:MaxMetaspaceSize=1m MetaspaceTest

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 :
Error occurred during initialization of VM OutOfMemoryError: Metaspace

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 :

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:

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.

Output :
Exception in thread “main” java.lang.OutOfMemoryError: Requested array size exceeds VM limit at com.codenuclear.ArraySizeLimitTest.main(ArraySizeLimitTest.java:5)

Leave a Reply

Your email address will not be published. Required fields are marked *