Tuning Your Java VM
Every java application needs some tuning to meet your requirements. Java VM has a lot of command line options, the most used of which are :
-Xms<n>[g|m|k] -> The initial and minimum size of the Java heap
-Xmx<n>[g|m|k] -> The maximum size of the Java heap
where the Java Heap size is the total size of the young generation space and old generation space. (we won't enter into detail here, see doc)
Because you know your server processor's type and memory size, most of the time you will put big values for those options even if there is no need to. Well I have 8GB of memory, so what's the big deal if I set an Xms of 4GB? Anyway, the values are chosen just because we have used them on other projects of the same caliber and no OutOfMemory was raised. But in the real world it is good to know why you have to set the heap size to some value.
Some lesser-known options are about permanent generation space.This area is only used by the HotSpot VM itself to hold metadata, such as class data structures, interned strings, and so on:
-XX:PermSize=<n>[g|m|k] -> The initial and minimum size of the permanent generation space.
-XX:MaxPermSize=<n>[g|m|k] -> The maximum size of the permanent generation space
If you use a lot of third party libraries , your perm space may become full and an OutOfMemory regarding permgen space will be given. So you will have to increase MaxPermSize , and because for Java 6 a default value is 64M, a new value of 128M will suffice.
The general ideea to tune your VM is that when your application was used from some time, meaning the memory size is big enough, to do a full GC to get some statistics. You know your application process pid from java status process tool (jps) or from any another OS command (like ps in linux). You can generate a full GC using java command jmap:
jmap -histo:live <pid>
If we want to see some GC info in our application stdout (or log) we need to start the application with some command line options :
-Xloggc:<filename> -> to capture GC data in a file
-XX:+PrintGCDateStamps -> to print the date time stamp when a GC is done
This will result in some output like :
2012-01-11T15:09:01.483+0200: [GC [PSYoungGen: 250408K->7194K(247872K)] 279260K->38759K(335296K), 0.0187385 secs] [Times: user=0.11 sys=0.00, real=0.02 secs]
Here we can see young generation and total footprint of memory before and after GC.
There are some GC algorithms which can be used by a Java VM. The following command line options allow to use a specific GC algorithm:
-XX:+UseSerialGC -> single threaded, young generation, and old generation garbage collector (should be used only for small Java heap sizes such as -Xmx256m or smaller)
-XX:+UseParallelGC -> only the young generation space utilizes a multithreaded (parallel) garbage collector.The old generation space uses a single-threaded garbage collector.
-XX:+UseParallelOldGC -> both young and old generations use multithread garbage collector.
-XX:+UseParNewGC -> enables a multithreaded, young generation garbage collector
-XX:+UseConcMarkSweepGC -> enables the VM’s mostly concurrent garbage collector. It also auto-enables -XX:+UseParNewGC (use if If you are not able to meet your application’s worst case latency requirements due to full garbage collection duration being too long)
-XX:+UseG1GC -> garbage first collector (default in java 7, can be also used in latest releases of java 6)
Practically by default, in Java 6 ParallelGC is used, and in Java 7 G1GC. Changing this algorithm must not be done in almost all cases.
When a jmap -histo:live command is issued, the following result will be seen:
[Full GC [PSYoungGen: 28393K->0K(321088K)] [ParOldGen: 101070K->107957K(204096K)] 129464K->107957K(525184K) [PSPermGen: 75396K->74999K(110208K)], 0.6012680 secs] [Times: user=1.68 sys=0.00, real=0.60 secs]
Here we can see young generation, old generation and permanent generation memory before and after GC. To know your application java heap size and permanent generation size you can use some general guidelines :
1) The initial and maximum Java heap size command line options, -Xms and -Xmx, should be set to a value between three and four times larger than the live data size of the old generation space (for previous output xms must be between 3*107957K ~ 323M and 4*107957K ~ 431M)
2) The initial and maximum permanent generation size, -XX:PermSize and -XX:MaxPermSize, should be 1.2x to 1.5x larger than the live data size of the permanent generation space (for previous output permSize must be between 1.2*74999K ~ 90M and 1.5*74999K ~ 112M)
You must have in mind only one thing:
The more data you collect, the better the estimate for a Java heap size starting point.