Wednesday, October 01, 2014

JVM Performance Tuning

On a multi-processor machine with 8 CPUs, here are typical settings:

On a 8 processor
java 1.6 update 45

 Heap Size: -Xms2g -Xmx2g  
 Perm Size: -XX: PermSize=512m -XX: MaxPermSize=512m  
 Newgen Size(Fixed Size) : -Xmn1g  
 Garbage Collector(Parallel): -XX:+UseParallelOldGC -XX:ParallelGCThreads=8 -XX:LargePageSizeInBytes=4m -XX:+UseCompressedOops  
 GC Statistics: -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps - Xloggc:/appserver/Weblogic/admin/360control_perf_domain/mserver/360control_perf_domain/logs/gc_360control.$(date +"%Y-%m-%d").log  


http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html

http://www.petefreitag.com/articles/gctuning/
http://java.sun.com/docs/hotspot/gc1.4.2/faq.html
http://java.sun.com/developer/technicalArticles/Programming/turbo/


The garbage collector first performs a task called marking. The garbage collector traverses the application graph, starting with the root objects; those are objects that are represented by all active stack frames and all the static variables loaded into the system. Each object the garbage collector meets is marked as being used, and will not be deleted in the sweeping stage.

The sweeping stage is where the deletion of objects take place. There are many ways to delete an object: The traditional C way was to mark the space as free, and let the allocator methods use complex data structures to search the memory for the required free space. This was later improved by providing a defragmenting system which compacted memory by moving objects closer to each other, removing any fragments of free space and therefore allowing allocation to be much faster:

For the last trick to be possible a new idea was introduced in garbage collected languages: even though objects are represented by references, much like in C, they don't really reference their real memory location. Instead, they refer to a location in a dictionary which keeps track of where the object is at any moment.

Fortunately for us – but unfortunately for these garbage collection algorithms – our servers and personal computers got faster (and multiple) processors and bigger memory capacities. Compacting memory areas this large often was very taxing on the application, especially considering that when doing that, the whole application had to freeze due to the changes in the virtual memory map. Fortunately for us though, some smart people improved those algorithms in three ways: concurrency, parallelization and generational collection.


Generational garbage collection

In any application, objects could be categorized according to their life-line. Some objects are short-lived, such as most local variables, and some are long-lived such as the backbone of the application. The thought about generational garbage collection was made possible with the understanding that in an application's lifetime, most instantiated objects are short-lived, and that there are few connections between long-lived objects to short-lived objects.

In order to take advantage of this information, the memory space is divided to two sections: young generation and old generation. In Java, the long-lived objects are further divided again to permanent objects and old generation objects. Permanent objects are usually objects the Java VM itself created for caching like code, reflection information etc. Old generation objects are objects that survived a few collections in the young generation area.

Since we know that objects in the young generation memory space become garbage early, we collect that area frequently while leaving the old generation's memory space to be collected in larger intervals. The young generation memory space is much smaller, thus having shorter collection times.

An additional advantage to the knowledge that objects die quickly in this area, we can also skip the compacting step and do something else called copying. This means that instead of seeking free areas (by seeking the areas marked as unused after the marking step), we copy the live objects from one young generation area to another young generation area. The originating area is called the From area, and the target area is called the To area, and after the copying is completed the roles switch: the From becomes the To, and the To becomes the From.

In addition, the Java VM splits the young generation to three areas, by adding an area called Eden which is where all objects are allocated into. To my understanding this is done to make allocation faster by always having the allocator reference to the beginning of Eden after a collection.

By using the copying method, garbage collection achieves defragmentation without seeking for dead memory blocks. However, this method proves itself to be more efficient in areas where most objects are garbage, so it is not a good approach to take on the old generation memory area. Indeed, that area is still collected using the compacting algorithm – but now, thanks to the separation of young and old generations, it is done in much larger intervals.


OutOfMemoryError (on HeapSpace, PermGen) and JVM Performance Tuning
HeapSpace OutOfMemoryError:


"Exception in thread "main" java.lang.OutOfMemoryError: Java heap space"

Most of you would have encountered this error before. This means JVM's usage of heap space exceeded what you specified in -Xmx vm argument or the default max heap size (if you did not specify one).

When you get this error, before you increase your -Xmx value, make sure to profile your application and see whether the usage is justified or if there is any memory leak. See below section on profiling tools.

PermGen OutOfMemoryError:

"java.lang.OutOfMemoryError: PermGen space"

Sometimes, you would also get a different kind of out of memory error. In JVM heap, there are different generations - Young, Tenured and PermGen. Young and tenured generations are where the regular objects from your application are stored. Size of young + tenured generation is controlled by -Xmx variable you saw above. PermGen is where JVM stores string pool, metadata about your application's classes etc.,

This error would normally happen only if your application loads a large number of classes, but is not unloading for some reason, which could be either legitimate or a memory leak. Also, make sure to check if your application heavily uses String.intern(), which could also contribute to this error.

No comments: