Tuning big java heap and linux huge pages
I recently had to run a jvm with large heap size, without getting into technical details we need the jvm to carry about 25G of cached memory that we load on stratup, so we want to start the jvm with 30G of minimum and maximum memory. we have a 64G 16DC machine running centos 5.5. the machine is running both our application on tomcat and a postgresql database.
what ever we did we couldn't start the jvm with more then 25G with -Xms25g -Xmx25g, apparently the jvm needs contiguous memory blocks, and even with 64G physical memory the OS can't find 30G of contiguous memory,although free -m shows that there are more then 45G available. we even tried starting the machine without postgresql on startup and then try to allocate the jvm heap but it didn't help, 25G is the maximum we could do. and we tried it with sum jvm, ibm and jrockit, they all behave the same way.
one solution suggested in this post was to increase the swap area, it did the job and after adding a large swap file we could allocate 30G and even 40G heap size. but this will be swapable memory which could hurt performance really bad, we wanted to have a non swapable memory.
So we decided to drop the swap file and use a linux kernel feature called 'Huge Pages', available since 2.6.18. (find more about it here and here and here).
Huge pages is about allocating larger memory pages then the default 4k, a page size is hardware+arch dependent and in our machine its 2M. You usually see Huge Pages used by heavy weight servers like oracle, mysql and WebSphere.
But whats more relevant to us is that you can ask the linux kernel to reserve a certain amount of huge pages to be used by applications that explicitly ask the OS to use huge pages, this memory will not be available to other applications. and the best thing is that huge pages are not swapable and always reside in physical memory. this sounds good especially that our application needs to keep a large amount of memory for as long as it lives.
I'm not going to explain how to setup huge page support, you can find good howto here , here and here and this is a calculator.
so because we wanted to be able to allocate 30G for the jvm we configured the kernel to reserve 17920 huge pages , our page size is 2M so we have 35G of huge pages reserved.
then add a jvm argument -XX:+UseLargePages, and we can now start the jvm with 30G or more of heap size with no problem.
after starting the jvm this is our huge page info:
[root@localhost ~]# cat /proc/meminfo |grep Huge
HugePages_Total: 17920
HugePages_Free: 9156
HugePages_Rsvd: 7365
Hugepagesize: 2048 kB
The problem is that now there is no memory available to start any application, even 'java -version' will fail to allocate memory unless you start it like: java -Xms12m -Xmx12m -XX:+UseLargePages -XX:LargePageSizeInBytes=2m -version
Now we are going on tuning this jvm for best performance, I will be happy to hear your ideas and I will continue editing this post as we improve our large heap jvm performance.

Comments
Fascinating, thanks for the excellent post. Some questions:
Is the JVM configured to use the parallel garbage collector. ? how many GC threads? with this configuration how long is the avergae garbage collection of the “Young Generation” and the “Old Generation”?
Correct me if I am wrong, when using large pages you are forcing the user to be a super user on Linux right?
:)
We haven't set any GC parameters yet, we are planing to and We'de love your advice.
No, we are running tomcat under non privileged user. you have to configure the maximum locked-in-memory address space that this user can call to be the at least the amount of memory you want, and the group that's allowed to use huge pages with vm.hugetlb_shm_group.
It depends on the number of CPU's your using. The best way would be to start with a base line, measure, make changes, test and try to reach a conclusion. Sure it takes a lot of time but there is really no other rout here.
(many GC options explained)
https://wiki.jasig.org/display/UPC/uPortal+Heap+Tuning
(jstat and more for GC tunning)
http://www.tikalk.com/java/java-performance-tuning-session-full-tutorial
http://www.tikalk.com/java/performance-tunning-case-study
http://www.tikalk.com/java/forums/tomcat-performance
http://www.tikalk.com/java/performance-tuning-session-links
http://www.tikalk.com/java/forums/tomcat-performance
Talk to me :)
Thanks, I'll use it.
Interesting indeed... 10x for sharing
As for the GC tuning - unfortunately there is no one size fits them all cookbook and it higly depends on your system's requirements and behaviour. "It's more an art..."
As Shlomo suggested, make sure you have a good grasp of HotSpot generations, ergonomics and available options:
http://www.oracle.com/technetwork/java/gc-tuning-5-138395.html
Anyway, try to use the latest avialable JDK (or 1.6u16 at least) as there have been many improvements and many options are set automatically according to the host platform (and getting better...)
Finally, I suggest you give a shot to G1 and other "experimental" options:
http://www.oracle.com/technetwork/java/javase/tech/g1-intro-jsp-135488.html
Keep us posted...
If you're running large memory heaps on Linux, I would offer you check out Azul's Zing JVM: www.azulsystems.com/products/zing/whatisit
Zing eliminates performance, scalability, and response time problems you'll inevitably face when using large Java heaps. Zing is simply used as your JVM instead of HotSpot or OpenJDK.