How do you determine a good MaxPermSize?

I know I'll probably get beat up for not knowing my JVM Turning parameters. I admit that I should know them better than I do. Hopefully this post will help us all understand them a bit better.

Ever since I upgraded appfuse.org to AppFuse 1.9.1, it's been experiencing OOM issues. They've been so bad that the site is lucky if it stays up for more than an hour. I've done a fair amount of performance testing on a single AppFuse application (and gotten very good numbers), so I was pretty puzzled by the whole situation.

To reproduce the problem, I downloaded all 5 demos to my machine and began profiling with JProfiler. Nothing stood out, but I was able to reproduce the problem by clicking through all the different applications. While testing, I had my JAVA_OPTS set to -Xms256M -Xmx384M.

After staring at JProfiler for hours, I gave up and sent my findings to the AppFuse mailing list. After going back and forth with several ideas, Sanjiv came up with the winner.

Did you try increasing the max perm size (-XX:MaxPermSize=256m)? Max Perm size is running out of memory and not necessarily the main memory. Class metadata stuff is placed in the perm memory (google for more details) and since we're using Spring, Hibernate and Tapestry which all use a lot of reflection, proxying etc, it's not surprising that max perm size is running out of memory.

Based on his advice, I added -XX:MaxPermSize=256m to my JAVA_OPTS, fired up JProfiler/Tomcat and began hammering my local instance with WAPT. 15 minutes later, with 20 simultaneous users, the heap and memory were humming along nicely with no issues. I made the change on appfuse.org and it's been up every since.

This experience has motivated me to start adding "-XX:MaxPermSize=256m" to all my JAVA_OPTS. Is this a good idea? If so, is 256m a good value to use? If not, what's the best way to determine (or guess) the proper value for this setting?

Posted in Java at Apr 19 2006, 09:54:14 AM MDT 21 Comments
Comments:

I've had a similar issue with Tomcat and set -XX:MaxPermSize=128m" and the problem went away. This was a portal server having several webapps all using Spring & Hibernate independently. So I imagine that 128m is sufficient for most circumstances. Hopefully someone else can chime in with some technique to better approximate a value...

Posted by Stephen Duncan Jr on April 19, 2006 at 11:10 AM MDT #

for JVMs running on a Solaris server, there is a -Xnoclassgc option, that disables class garbage collection (there is no cleaning of the perm gen with this option turned on), leading to out of memory errors if your application uses reflection, proxies, etc...

Posted by guillaume carré on April 19, 2006 at 11:11 AM MDT #

Matt, you should turn on the -Xloggc:gclogs.txt flag, and also the -XX:+PrintGCDetails flag.

The combination of these two flags will allow you to see how much GC is happening, which generations are taking up how much memory, and yes, how much the PermGen is taking up. You should watch your running applications over a period of time to see how they handle memory in order to get a real idea of what GC flags to use.

-M

Posted by Moazam on April 19, 2006 at 11:49 AM MDT #

You need to look at some -verbosegc output to determine what the optimum settings should be. JConsole also looks like it could help in this area.

Posted by Matthew Fleming on April 19, 2006 at 11:56 AM MDT #

If you didn't have this setting tuned before then going to 128 is probably fine as the default is 64MB (assuming 1.4.2 + VM). It all depends on the number of dependencies but 256 is most likely more than needed as a general rule.

Posted by Peter Thistleton on April 19, 2006 at 01:12 PM MDT #

Is this a sign that libraries are getting too bloated? Or too many dependencies being loaded? Wondering if tuning isn't the *real* answer, just treating the symptoms... Thoughts?

Posted by gerryg on April 19, 2006 at 04:33 PM MDT #

You have to generate the logs and data before you can find whether your libraries are 'bloated'. Setting up Xloggc/verbosegc/PrintGCDetails is not tuning, it's just data gathering. Once you have that information, then you can figure out where to go from there. -M

Posted by Moazam Raja on April 19, 2006 at 05:50 PM MDT #

Yes this will increasingly become a problem. I only just came across it myself. More and more people are pushing against javas limitations by doing bytecode generation, proxying and so on (it is getting easier to do) yet classes don't seem to be loaded and treated the same as "normal" objects, which I think is a pity. As metaprogramming in java becomes popular, something has to give. We have to expect that more and more apps will be creating and discarding thousands of little classes in their lifetime. I would love to hear from someone in the know what the future directions for this are... I doubt there are many apps out there any more (new ones that people are building that is) that are just using the classes that were hard coded, ie no proxies, aspects, code generation on the fly, bytecode mods etc...

Posted by Michael Neale on April 19, 2006 at 11:45 PM MDT #

This is an implementation detail in the Sun JVM. BEA JRockit doesn't have the concept of a permspace, nor do - if I remember correctly - IBM's JVM. So one workaround if you have this issue would be to try a JDK from a different vendor. Henrik -- JRockit team

Posted by Henrik Ståhl on April 20, 2006 at 12:03 AM MDT #

Interesting.. yeah it would be a Sun thing... how do others (like JRockit) do it? Is it more accomodating to metaprogramming and the associated class generation?

Posted by Michael Neale on April 20, 2006 at 12:49 AM MDT #

JRockit stores class related data on the heap, subject to GC as any normal object. I don't know about IBM, but it's not farfetched to assume some similar solution.

Posted by Henrik Ståhl on April 20, 2006 at 01:04 AM MDT #

Don't simply leap to the use of any particular JVM parameters to solve the problem until to properly analyze the problem - especially those that simply increase the max memory in any particular space of the JVM. The best tools I've found to do this include HPjtune, GCViewer and the best one of all is by far visualgc which ships with jvmstat. I've found that HPjtune and visualgc are invaluable when analyzing overuse of memory.

Incidentally, and this is obvious, but if you just upgraded the software and the OOM errors just started, you can bet that you're abusing memory somewhere in the new release.

Posted by Bruce Snyder on April 20, 2006 at 03:44 AM MDT #

Bruce, I am not sure if all that applies to Classes, sure to everything else, but in hotspot, classes are treated very differently at least...

Posted by michael on April 20, 2006 at 06:23 AM MDT #

<em>> if you just upgraded the software and the OOM errors just started, you can bet that you're abusing memory somewhere in the new release.</em>

Yeah, but unfortunately nothing has really changed in AppFuse - except for upgrades to Tapestry 4.0 and WebWork 2.2. I suspect that Hivemind and WebWork's tighter integration with Spring might be eating up more memory. Regardless, the site has been up ever since I made this change. So regardless of what's happening, increasing the MaxPermSize fixes it.

Posted by Matt Raible on April 20, 2006 at 06:09 PM MDT #

I ran into this problem a while back... a site I was working on had over 80,000 individual JSPs, which were mostly the same (oh, how I cried about DRY, and just cried in general...). Unfortunately, they weren't interested in replacing the lot with a simple decorator such as SiteMesh (sigh...). Anyway, the quick n dirty calculation I did was to write a small shell script to count the entire size of all the .class files that were in the Tomcat work directory - I figured these all need to reside in the permanent heap, so the minimum size needs to be whatever that value is. I added another 32MB onto that figure, to allow for expansion. Seems to have worked. FWIW, it was around 350MB (!!!!!). In that situation, thats not my recommended fix, btw - the recommneded fix is the fix the damn thing properly, not patch it up until you reach the MaxPermSize limitations again...

Posted by Lee on April 24, 2006 at 03:24 AM MDT #

perhaps this might explain why its happening
http://bugs.sun.com/bugdatabase/view_bug.do;:WuuT?bug_id=4957990

This can be solved by
  1. using a client VM instead of a server VM will solve the issue
  2. using 128m for MaxPermSize but not the default 64m

Posted by Chandra Poluru on April 27, 2006 at 09:37 AM MDT #

I also had these annoying Perm Gen Space OOMs when redeploying webapps. I'm using spring 1.2.8, Hibernate 3 (both with CGLIB 2.1_3), tomcat 5.5.17 and - now the problem: jdk1.5.0_06. After upgrading to jdk1.5.0_07 my Perm Gen Space gets gc'ed like it should be - no increase of Perm Gen Space, no code changes.

There were however some learnings on the way:

1. Put JDBC driver in common/lib (as tomcat doku says) and never ever in WEB-INF/lib - If you get No suitable driver Exception during redeploy use JNDI DB definition in META-INF/context.xml; not in server.xml and not in conf/Catalina/localhost/<context>.xml. This is how my META-INF/context.xml looks like:

<Context path="/ngc" reloadable="true" debug="1">
	<Resource
		name="jdbc/db"
		auth="Container"
		type="javax.sql.DataSource"
		maxActive="30"
		maxIdle="3"
		maxWait="10000"
		username="webapp"
		password=""
		driverClassName="net.sourceforge.jtds.jdbc.Driver"
	url="jdbc:jtds:sqlserver://dbdevel/ngc;tds=8.0;lastupdatecount=true" />
</Context>


2. Don't put commons-logging into WEB-INF/lib since tomcat already bootstraps it

3. If you still run in Perm Gen Space OOM then you may have to increase Perm Gen Space or don't redeploy your webapps so fast! What was most irritating for me after thinking the issue is solved for me was that sometimes i did ran into Perm Gen Space OOM and sometimes not. It seems that gc cleans Perm Gen Space from time to time and not (!) if space is low or app explicitly requests gc. - But this I didn't fully understand (not to say not at all), but still there are reasonable arguments on sun bug database to increase this memory (see post above)

Now I'm happy again after two (!) days of reading lots of forum threads, learning lots about class loader, tomcat, spring, hibernate, aop and class metadata and knowing that programming still can be very difficult!

Posted by Yan Hackl-Feldbusch on June 29, 2006 at 02:08 AM MDT #

In our appplication,we are using maven build tool,and we are getting permgenspace running out of memory,eventhough i increased mjy permgenspace memory ,its giving the same problem,so i eventually seperated the target for junits and the src codes.for srs its giving no problem,its building but for junits ,it is not hitting the target i.e not building the junits.so in the project.xml is this mandatory to specify the junit target just below src target .Need help

Posted by iniya on February 18, 2007 at 11:31 PM MST #

I use "-Xms512M -Xmx512M" in my MAVEN_OPTS environment variable. Since adding this, I haven't had any OOM issues (with Maven 2) in the year that I've been using it.

Posted by Matt Raible on February 18, 2007 at 11:34 PM MST #

I have started seeing this error on a new application. The issue is I am using DailyRazor web hosting and the JVM heap is 160MB. If I set the perm gen size to 128 that doesn't leave much heap does it? The remainder is 32mb which I know isn't enough. I don't understand why web hosts don't provide for more heap size.

Posted by Patrick Dezenzio on October 30, 2007 at 09:56 AM MDT #

Patrick, I just read that the perm gen size is separate from the 'regular' heap. See http://www.unixville.com/~moazam/stories/2004/05/17/maxpermsizeAndHowItRelatesToTheOverallHeap.html.

Posted by Maarten Brugman on January 17, 2008 at 07:42 AM MST #

Post a Comment:
  • HTML Syntax: Allowed