CFMX JVM Tuning - The difference between MaxPermSize and Heap Size

As a result of the CFMX/Commonspot upgrade I blogged a few days ago, I've been troubleshooting some CFMX crashing problems along with "java.lang.OutOfMemoryError" errors and have been tuning the JVM settings for the servers. Along the way I ended up doing a good bit of research on JVM settings and what the differences are between the Heap Size and the MaxPermSize. It's fairly well documented on various blogs and discussion lists that both the JVM Heap Size and MaxPermSize are important when dealing with "out of memory" errors in CFMX, but I've never really completely understood what these setting or their values mean. First off, what is the JVM Heap? The heap is memory that's been allocated to store Java classes and objects. The JVM heap is split up into several areas and newer/older objects are shuffled between the sections based on their age and use. The shuffling of object occurs during Garbage Collection, a process which also discards objects which are no longer used. Depending on system settings, garbage collection runs now and then, cleaning up objects and shuffling them around. More great information on Garbage collection in CFMX can be found on Brandon Purcell's blog and in Sun's tuning article on garbage collection (via Tom Link). About heap size - it's generally a good idea to set the JVM's max heap size to at least 512, and no matter what the max is, the initial heap size should be set to the same value. Making these settings the same value prevents the JVM from frequently re-sizing the heap as it grows, something that can trigger frequent garbage collections and can degrade performance. So when does it make sense to increase the JVM heap to a value larger than 512? Generally, no-one cares about this value till they start to get java.lang.OutOfMemoryError messages, and perhaps that's why you are reading this. If the JVM heap size is set too small, the server's memory slowly fills up and eventually an object is created and there's no more room in memory for it. This becomes the proverbial straw that breaks the camel's back and will cause your server to crash. Inversely, if you set the value too high, alot of junk objects build up in the heap and garbage collection can take a long time cleaning it up. This can cause a serious degradation in performance. Again, I'll point at Brandon Purcell's blog for more help in finding the right size for the heap, though it also work to just adjust the heap size and watch the server for errors or performance problems. That's a description of the heap, but what about this other setting set with -XX:MaxPermSize? Turns out this sets the size for something called the "Permanent Generation". A good definition for the Permanent Generation is found in the Sun article Frequently Asked Questions about Garbage Collection in the HotspotTM JavaTM Virtual Machine:
The permanent generation is used to hold reflective of the VM itself such as class objects and method objects. These reflective objects are allocated directly into the permanent generation, and it is sized independently from the other generations. Generally, sizing of this generation can be ignored because the default size is adequate. However, programs that load many classes may need a larger permanent generation.
So the permanent generation contains information about the objects in the heap. Ah-ha! Now we can start to understand how these two numbers are related to each other. The heap stores the objects, and the permanent generation keeps track of information about the objects. Consequently, the more objects there are in the heap, the more information there is to be tracked about them, and the larger the permanent generation needs to be. Another quote from Sun's documentation comes in handy here:
For most applications the permanent generation is not relevant to garbage collector performance. However, some applications dynamically generate and load many classes. For instance, some implementations of JSP(TM) pages do this. If necessary, the maximum permanent generation size can be increased with MaxPermSize.
This also applies to compiled ColdFusion class files. If there are alot of class files in /coldfusionmx/wwwroot/WEB-INF/cfclasses/, then you'll likely need to increase the MaxPermSize setting. Following this logic, if you have an application server with a large number of small class files, you are likely to need a larger MaxPermSize than if you have a server consisting of a small number of large class files. Note: Instructions on increasing the MaxPermSize are found in this ColdFusion MX: Tips for performance and scalability Technote. As it turns out in my recent Commonspot/CFMX upgrade, the new codebase must have generated more classes, or at least had more information generated by those class files. Even though the heap size was still large enough after the upgrade, I had to change the MaxPermSize from 128 to 256 to make the java.lang.OutOfMemoryError plaguing the site go away. Hopefully this explanation will come in handy for others tuning their memory settings! Added 4:14PM 5.28.04 Note: Important tidbit I forgot to add into this post initially - The MaxPermSize is in addition to the Heap, so if you add both of the numbers together you'll get the total size Jrun/CF should consume before blowing up.

Comments (11)

Add Comment ]

Charles Chapman Thanks for posting this. Very good explanation of everything that is going on. We are fighting through the same problems so at least I now have a better understanding of what is going on.
Tom Link Looks good. Just a point of clarification... You say "This also applies to compiled ColdFusion class files. If there are alot of class files in /coldfusionmx/wwwroot/WEB-INF/cfclasses/, then you'll likely need to increase the MaxPermSize setting."
Since CF templates are compiled to java classes, another way to say this is that "if there are alot of templates (and/or CFC methods) in the application(s) on the server, you'll likely need to increase the MaxPermSize setting."
Christian Cantrell Ah, yes. The old java.lang.OutOfMemroy errors. Join the club:

http://www.markme.com/cantrell/archives/002181.cfm

Glad you got it worked out, and thanks for the valuable explanation.
Robi Sen Here are my JVM recommendations for JVM settings

Drop +UseParallelGC. JVM 1.4.+ will use ParNewGC in a multiprocessor environment or the JVM will use the DefaultNew GC if the machine is uniprocessor (DefaultNew is more efficient than the parallel collectors, ParNew, on 1cpu machines).

Add these options to the JVM settings: -XX:MaxPermSize=128m -XX:PermSize=64m -XX:+UseConcMarkSweepGC -XX:NewSize=48m

Its actully pretty important on larger sites to make sure you set the PermSize in that you can get some really long 'stop the world' pauses while the JVM cleans up.
Cameron Childress Good note on the PermSize setting. It's worth noting that I've seen systems where MaxPermSize needs to be even higher than 128m, though setting it to 128m will help on most systems.
Robi Sen Which is why you have to monitor the JVM and you should be load testing your system with realistic tests and then tuning from there. Although I recently just made some changes to the JRUN.XML as well as what I consider good 'default' JVM settings and saw responce time and CPU usage drop by 25 and 20 percent respectivley! I tested that through loadtesting but I did not have much time to tune from there. But those are some nice numbers from some really simple changes!!
Tom Is there a way to find out this size of all your application variables from CF? Or current memory allocation? I want to modify my CF caching if I am using to much RAM.

Also, as for max perm size, does anyone know how many templates (approx) need 128mb?
malleswar Anybody Please let me know the commnds to monitor/set the heapsizes
thanks in advance
robi Here are some links

http://www.robisen.com/index.cfm?mode=entry&entry=FD4BE2FC-55DC-F2B1-FED0717CC1C7E0AF

http://www.robisen.com/index.cfm?mode=entry&entry=39E0B0C6-55DC-F2B1-FBBDB70CEC963D6D

http://www.robisen.com/index.cfm?mode=entry&entry=67789980-55DC-F2B1-FDEDE3B28F0E7A62

You really should read through the SUN JVM tuning faq. What are you trying to do? Solve a problem, tune your system for stability or performance, scale a application? Depending on your application and what you are doing you will want to have diffrent settings and its very much a unquie thing per system but the first link should give you a general idea. You should also profile your system first using some sort of automated load testing software as well as JVM monitoring tool like Jprofile or even JVMStat. Then you can get a base line of your system and see how its using memory. After that making changes makes sense. If you want to email me at robisen AT gmail DOT com I would be happy to send you a presentation on this topic as well as help you with your specific situation.
Patrick Hayden Thanks for this useful summary. I was particularly interested in is your last comment that the MaxPermSize is in addition to the heap. Do you have any references to confirm this? The information in the Sun FAQ that the permanent generation is "sized independently from the other generations" would seem to indicate that your comment is correct.
robi Patrick just read the links. Cameron is correct in the sense that Xms and Xmx bound the minimum and maximum that the JVM will use at run time for your application but the Perm Generation is where long term objects such as Java classes the JVM needs, Java Classes that make up the acutal CF systems as well as some other classes reside.
Not providing enough room for these classes is a common reason JVM's run out of mem under load.
Also a couple of quick comments to camerons post
1. you should use proper testing procedures to size your Xmx settings in that you can set your Xmx so large that garbage collection takes longer than it needs. A good rule is dont set your Xmx higher than 25% of what it uses under load but once again test and find the right setting for your app.
2. cameron says ' Making these settings the same value prevents the JVM from frequently re-sizing the heap as it grows, something that can trigger frequent garbage collections and can degrade performance.' actually this is not the reason since there is nothing wring with doing Xms 512 and Xmx 768. The reason to set them the same is heap fragmentation.
3. Another comment is.. hardly anyone tunes the young generation yet its usually the most used generation in a web app since thats where all initial web requests are created and destroyed. Usually the JVM will size this well for you but I often go ahead and test it with a minimum of about 20 to 25% of the total heap for a system i know will have heavy load. Often when i find my optimal settings I then make the young gen min and max the same once again for heap fragmentation reasons.

Add Comment ]

Post a comment





Leave this field empty: