Archive for the ‘JVM memory organization’ Category

JVM Memeory Tuning

May 22, 2010

Java virtual machine or JVM as it is properly known provides the execution environment to the Java applications. One of the most critical factors that affects the performance of a Java application is the memory organization and behavior of the JVM. Most often the JVM is not tuned before the application is deployed in production. At most, the heap size is set according to the application but none of the other parameters are looked at. This post aims to provide a basic understanding of JVM memory organization and explains few of the basic parameters that can be tuned to get enhanced and optimized performance.

The above image shows the basic organization of the JVM memory. The JVM is divided into 2 generations:

1) Young generation

2) Old generation

The young generation is further divided into the following parts:

a) Eden space

b) Survivor space I

c) Survivor Space II

The heap is designed so that objects that are created and destroyed quickly are clean up easily. Objects that live for a long time are difficult to clean up, but that is done much less frequently. The following steps describe how the garbage collector moves objects around and eventually frees them:

  1. Objects are created in Eden
  2. When Eden becomes full, live objects are copied to the first survivor space; dead objects are then discarded
  3. When the first survivor space is full, then live objects are copied to the second survivor space; dead objects are discarded
  4. When the second survivor space is full then all of its live objects are tenured, or retired, to the old generation; dead objects are discarded
  5. When the young generation is full and there is not room to copy objects to the old generation, then the garbage collector walks through every object in the old generation and discards objects that are dead. During this time, nothing running in the JVM can do anything; this is referred to as a “stop-the-world” collection

The reason that the default heap is not configured properly is because the young generation is too small and the survivor spaces can be measured in kilobytes, not in megabytes. Objects are created and retired to the old generation well before they can be collected.

Given below is a sample initial recommended configuration for the heap, based off the total size of the heap:

  • The young generation should be “a little less” than half the size of the heap. If it is greater than half the size of the heap, you have to use full or major garbage collections to clean it up
  • The survivor spaces should be no smaller than one tenth the size of the young generation
  • The sizes should be fixed for a production environment (set the min and max to the same values), so that you do not require the heap to grow when it needs to (that is, when it is under stress)

Putting this into command line arguments that you can send to your JVM, consider a 1GB heap (1024MB):


The following breaks down what each option means:

  • Xms1024m, Xmx1024m: This sets the minimum (ms) and maximum (mx) heap size to 1024 megabytes
  • XX:NewSize=500m, XX:MaxNewSize=500m: This sets the young generation to occupy 500 megabytes. Note that XX:NewSize sets the minimum size and XX:MaxNewSize sets the maximum size of the young generation. With this configuration, it is fixed.
  • XX:SurvivorRatio=6: The purpose of the survivor ratio is to determine the sizes of the survivor spaces, but the number is a little misleading. Setting the value to 6 means that each survivor space will occupy one eighth of the young generation. The number 6 means that Eden occupies 6 units of the young generation, and the survivor spaces each occupy 1 unit, for a total of 8 units

After making the changes to the heap it should be monitored either using utilities like jConsole or the gc logs should be generated. The gc logs can be generated by passing the either of the below mentioned options to the JVM start up:

These logs can then be anlyzed using any available GC viewer.

During the analysis we find that the heap repeatedly climbs quickly and falls, there is still too much major garbage collection occurring. In that case, you need to increase the size of your survivor spaces (decrease the XX:SurvivorRatio) value.

Permanent Generation is another area that is used to load classes into; note these are the actual class file, not the class instances.

The JVM uses the class files that are loaded into the permanent generation in order to create class instances that are placed into the heap. If the permanent generation is sized too small, it must unload class files to make room for new ones before it can create new instances. This is a performance hit at runtime, while the heap is unloading classes. The default value is 4MB for permanent generation that is too small for enterprise applications. Depending on the number of classes you can increase this value to 32MB or upto 128MB.



This marks a conclusion to this post. The aim was to give a basic understanding of the JVM memory organization and showcase the basic parameters that can be tuned. In my next post I will talk about another important factor that has immense impact on the JVM and application performance. This factor is Garbage collection. We will talk about its importance, how it works and different algorithms that can be configured.