====== Java (jvm) tips and tricks ======
===== Enviroment settings =====
==== Linux (with multiple java enviroments) ====
''.bashrc'' / ''bash.profile''
export JAVA_HOME="/usr/local/java/"
export PATH=/usr/local/java/bin:$PATH
===== Tuning =====
{{ :memoryjvm.png?nolink |}}
^ switch ^ description ^
| **-Xmx** | **Maximum Java heap size** - defines the maximum memory size that the heap can reach in the JVM. You must know your program well and see how it performs under load and set this parameter accordingly. A low value will probably cause OutOfMemoryExceptions or very poor performance if your programs heap memory is reaching the maximum heap size. On a dedicated server this should be set as high as available memory allows (within reason). |
| **-Xms** | **Initial Java heap size** - sets the initial heap memory size for the JVM. This means that when you start your program the JVM will allocate this amount of memory instantly. This is useful if your program consumes large amount of memory right after starting up. This avoids constant heap expansion (via memory reallocations) and result in significant performance gains at startup if the program does alot of small allocations. If you don't know if this parameter is going to help you, **don't use it**. |
| **-Xmn** | **Size of the heap for the young generation** - young generation represents all the objects which have a short life of time. Young generation objects are allocated in a specific location into the heap, where the garbage collector will pass often. All new objects are created into the young generation region (called "eden"). When an object survives after more than 2-3 gc cleaningsit will be moved into "survivor" heap space and later to "tenured" space. Small eden size speeds up GC passes, however you need to make sure you can fit short-lived objects into that space. Good size is 33% of all heap space. |
| **-Xss** | ** Stack size for each thread ** - This sets size of preallocated stack for each thread. If you set this too low your program will crash with StackOverflowExceptions. Setting this too high will cause excessive memory usage - this amount of memory gets allocated for **each** thread in the JVM. The default for most JVMs is 512k. Note: When increasing this number on Linux, you will probably have to also increase native stack size to same amount with "ulimit -s" |
| ||
| **-XX:NewRatio** | Same as Xmn, but using a % (dynamic fs static -Xmn option) **-XX:NewRatio=3** means that the ratio between the old and young generation is 1:3 |
| **-XX:NewSize** | Size of the young generation at JVM init. Calculated automatically if you specify -XX:NewRatio |
| **-XX:MaxNewSize** | The largest size the young generation can grow to (unlimited if this v alue is not specified at command line) |
| **-XX:SurvivorRatio** | "survivor" generation ratio, in %. For example, -XX:SurvivorRatio=6 sets the ratio between each survivor space and eden to be 1:6 (eden is where new objects are created) |
| **-XX:MinHeapFreeRatio** | When JVM heap usage reaches this percentage of allocated heap JVM will allocate additional memory up to the Xmx limit. When Xmx == Xms, it's useless. Default is 40%. |
| **-XX:MaxHeapFreeRatio:** | When JVM heap usage passes below this treshold, JVM will release allocated heap memory to the OS to avoid unecessary memory allocation. Default is 70%. |
**A nice gotcha...** \\
Full-heap major garbage collection **will not** run until the tenured part of heap is full. This means if you have heap size (Xmx) of 1024MB with 750MB of heap allocated and your program has only 250MB of objects actually reachable ("alive") GC **still** won't run until whole 1024MB of heap is filled up.
This is by design - it improves performance. Don't give JVM more heap space than you're actually willing to lose.
* It is good practice with server-side Java applications like Resin to set the minimum **''-Xms''** and maximum **''-Xmx''** heap sizes to the same value.
* For efficient garbage collection, the **''-Xmn''** value should be lower than the **''-Xmx''** value.
==== Choosing the garbage collector ====
In Sun/Oracle JVM you have a choice of three garbage collectors, each built for different use case.
* **Serial collector** - single-threaded, **+XX:UseSerialGC**
* **Parallel collector** - does small passes in parallel, **+XX:UseParallelGC** and **+XX:UseParallelOldGC**
* **Concurrent collector** - does most of the collection in other threads, minimizes pauses, **+XX:UseConcMarkSweepGC**
=== Serial collector ===
Is the efficient (no intra-thread communication) of the three. Stops the world while running collection.
**Best for**: applications running on single-core, applications with small datasets (up to 100MB), applications with no pause-time requirements
=== Parallel collector ===
Does minor collection (eden) in parallel thus greatly reducing garbage collection overhead on multi-core machines. With **+XX:UseParallelOldGC** is also does major collection and compation in parallel thus further reducing pause time for garbage collection on multi-core machines. It uses more memory and has slower full-passes than serial collector.
**Best for**: applications with medium to large datasets (100MB+), applications that run on multi-core machines, application where peak throughput is the priority and pauses of 1 sec are acceptable.
=== Concurrent collector ===
Does most of it's work concurrently while other application threads are still running. It keeps garbage collection pauses the shortest possible at the expense of total garbage collection time and increased memory usage. The maximum response time is achieved at the cost of total application throughput so this GC may reduce total application performance at the expense of maximizing response time.
**Best for**: applications with medium to large datasets (100MB+) which require minimal response time (with pauses required to be less than 1 sec).
** Concurrent GC on machines with 2 cores **
During each concurrent GC phase a whole core is pinned to the GC and is not available to the rest of the application. Due to long running passes of concurrent GC this may not be desireable on machines with only two cores.
Enabling **incremental mode** for concurrent GC will cause the GC to do each pass in several phasses while relinquishing CPU to the application inbetween. This causes the core to be available to the application for more time at the expense of further prolonging the GC passes. Incremental mode is enabled with **-XX:+CMSIncrementalMode**.
[[http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html|More information on Java GC tuning at Oracle.]]
===== Good/best practices =====
1. OpenJDK 1.6 and 1.7 may (as of now, 6. 12. 2012) still be unstable in stressful production environments leading up to segmentation faults and unintended behaviour. Use Sun/Oracle JVM for maximum stability and performance.
===== Examples =====
tying to limit jvm to ~2G of RAM (java x86_64)
java -Xms512m -Xmx2G -XX:+UseCompressedOops -server -XX:MaxPermSize128
java (i386)
java -Xms1400m -Xmx2G -XX:MaxPermSize=128m -server
===== Troubleshooting =====
=== Resolving java.lang.OutOfMemoryError: PermGen ===
if you get an error like:
java.lang.OutOfMemoryError: PermGen
The PermGen space is used for things that do not change (or change often). e.g. Java classes. So often large, complex apps will need lots of PermGen space. Similarly if you are doing frequent war/ear/jar deployments to running servers like Tomcat or JBoss you may need to issue a server restart after a few deploys or increase your PermGen space.
To increase the PermGen space use something like: **-XX:MaxPermSize=128m** //(The default is 64MB.)//
(Note that Xmx is separate from the PermGen space, so increasing Xmx will not help with the PermGen errors). \\
**The PermGen memory in addition to the Xmx memory. e.g. -Xmx128m and MaxPermSize=128m would use up to 256MB.**