Tuesday 3 June 2014

JVM Memory Leak



JVM Memory Leak

In this article, I will deep dive into one of the crucial area of any Java Application, i.e Memory. Any java application where either Garbage Collection(GC) techniques has not been looked upon or Memory size has not been looked upon is bound to suffer from Memory Leak one day.

Following sections will be covered in this article so that we have a both broad and in depth picture of Memory Leak and its surroundings:

1) Overview of Garbage Collection mechanism(GC)?
2) Overview of Memory Allocation to JVM?
3) What is Memory Leak?
4) How Memory Leak happens or Symptoms of Memory Leak?
5) How to prevent or avoid Memory Leak?

1) Overview of Garbage Collection mechanism(GC) -
Garbage Collection is one of the automatic JVM mechanism to look at the Heap memory, identify objects which are no longer in use and to delete unused objects.
It's basic purpose is to reclaim the heap memory from unused objects and makes space for future objects to be created.
So basically, GC is a two way process, one is to Mark the objects(unused,non-referenced) and second is to Delete these objects.

2) Overview of Memory Allocation to JVM -
JVM Heap space is divided into following categories:
a) Young Generation
                i) Eden Space
                ii) Survivor '0' Space (S0)
                iii) Survivor '1' Space (S1)
b) Old Generation
c) Permanent Generation(Perm Gen)



When a new object is created, it is first allocated space in Young generation. Based upon whether it is being referred or not during the time of GC, decision is made to move this object to next heap space or to delete it is made.
If at time of GC, an object is still has valid reference, then it is moved from Eden Space to S0 space. Gradually an object with valid reference during time of GC is moved forward to Old Generation.

So lifecycle of an object is like :
new Object -> Eden Space -> S0 space -> S1 space -> Old Generation.
At any time during GC, if object is unused, it will be deleted from its present heap space and memory will be reclaimed.

The Permanent Generation contains metadata required by JVM to describe the classes and methods.
Following are the contender of Permanent Generation space:
a) Methods in a class
b) Class Name
c) Constant Pool
d) Internal objects used by JVM

The classes that are no longer being used or unloaded are removed from Perm Gen space and memory is reclaimed.

3) What is Memory Leak -
A memory leak happens when JVM is unable to allocate memory to new objects. Directly it can be said, when even after multiple GC execution, memory space cannot be reclaimed and heap space gets full, a memory leak will happen.

4) How Memory Leak happens or Symptoms of Memory Leak -
One of the common symptom of Memory leak is when JVM throws OutOfMemoryError.
Other symptoms includes when responsiveness or performance of an application is getting degraded and after a restart of server, the performance rises.
But again after some duration, performance seems to degrade.

This usually happens because JVM is not able to match up with the requirement of space by new objects. As and when heap space gets full and if at the same time heap space is needed for a new object, OutOfMemoryError will be thrown up.

5) How to prevent or avoid Memory Leak -
First step is to identify the problem area and then use profiling tools to tackle them. One need to identify the problem with help of error in logs file if any.

Common error traces found in log file during Memory leak are as following:
a) java.lang.OutOfMemoryError: Java heap space
b) java.lang.OutOfMemoryError: PermGen space
c) java.lang.OutOfMemoryError: Requested array size exceeds VM limit
d) java.lang.OutOfMemoryError: request <size> bytes for <reason>. Out of swap space?

In this article, I will focus on first two heap error i.e Java Heap space and PermGen space error

Let's look into Java Heap space error first:

a) java.lang.OutOfMemoryError: Java heap space -
As specified in the error name itself, this error is thrown when heap space is full and GC cannot reclaim memory.

Few of the causes of OutOfMemoryError are as following:
i) GC not able to reclaim heap memory - This happens when application is holding continous reference to objects. This may be due to poor coding techniques followed.
To tackle this error following steps can be followed (not in order) :
                Step 1: Dry run of code - Look out for major bottleneck in code, specially objects creation in Loops.
                Step 2: Use Profiling tools - A free and easy to use profiling tool shipped with Sun JDK itself is JVisualVM (exe available in bin dir of jdk) - It represent a graphical view of classes, threads, objects getting loaded in your application. Target area should be CPU and Memory profiling tab. It will let you know about the threads/objects that are occupying most of the CPU time and Memory area.

ii) JVM Heap space allocation configuration - Sometimes it is difficult to reduce the number of objects creation after a certain limit, then it is the time to increase the heap space allocated to JVM.
Following are the heap space allocation parameters:
                a) -Xms - Minimum memory size
                b) -Xmx - Maximum memory size
                Specify same size for both a) and b)
                c) -XX:+HeapDumpOnOutOfMemoryError - To generate heap dump as and when out of memory occurs
                d) -XX:OnOutOfMemoryError=%ACTION_RESTART% - To specify action like restart server after out of memory error
               
b) java.lang.OutOfMemoryError: PermGen space -         
As specified in the error name itself, this error is thrown when Permanent Generation space is full and GC cannot reclaim memory.
This happens when classloader and its classes cannot be garbage collected after they have been modified/unloaded. Sometimes this error comes if application is using 3rd party jars like Spring, Hibernate, CgLib and the space allocated to PermGen is not sufficient.
These jars creates lots of Proxy classes at runtime, due to this unknowingly your PermGen space will get filled.

To avoid this error following below steps(not in order):
i) Configure JVM Options
                a) -XX:MaxPermSize=128m or higher - Increase as per need
                b) -XX:+UseConcMarkSweepGC
                c) -XX:+CMSClassUnloadingEnabled  - This will enable class unloading when it is no longer in use.
ii) Do not pass references of your application to utility jars in your application.
iii) Before selecting any 3rd party jar, evaluate its pros and cons on performance.