PermGen Strikes Back!
Thursday, March 15, 2007 3:34:58 PM
Bugger, bugger, bugger!
Just as I thought that the issue with the PermGen OutOfMemoryError was over, it turns out: it's not.
Here's why: by setting the -XX:MaxPermSize=128m, I was only postponing the eventual death of my app server. This postponing was apparently so good, that I didn't incounter the PermGen issue during my, ahem, "tests".
In fact, my "test" was not only manual, it was also naïve. What I did was to run the app server without the GC tuning parameters, and make redeployments until it crashed. Turns out I could make 5 redeployments with an app called Payout (named after my current project). Then I applied the parameters and redeployed again and again until I felt confident it worked. Apparently, I felt confident after 10 redeployments.
My failure was that I didn't do any actual measuring of the state of the memory in the JVM. :clown:
Nervous sysadmin
My sysadmin contacted me today and said that he was worried that the memory usage pattern hadn't changed significantly. The JVM was still, slowly but surely, eating up all its memory. I pointet out that the MaxPermSize had been increased, and the GC probably didn't bother to reclaim memory because there was still plenty of it available. My rationale was, that once the JVM got closer to the max, it would start to do more garbage collection.
And then, I started to feel like testing my claims.
I wrote a small web application that used the MemoryMXBean to plot the NonHeap memory stats to an array list every minute, and then print the list, CSV formattet, on a JSP file. I then followed the memory usage as I start to redeploy again and a again, to see what would happen when I reached the max. As you figured, I got PermGens.
Then I snatched the memory statistics from my little plotter app, and importedd it into Excel to generate this graph:

What have we learned?
Two things:
So I guess it's back to the drawing board!
Just as I thought that the issue with the PermGen OutOfMemoryError was over, it turns out: it's not.
Here's why: by setting the -XX:MaxPermSize=128m, I was only postponing the eventual death of my app server. This postponing was apparently so good, that I didn't incounter the PermGen issue during my, ahem, "tests".
In fact, my "test" was not only manual, it was also naïve. What I did was to run the app server without the GC tuning parameters, and make redeployments until it crashed. Turns out I could make 5 redeployments with an app called Payout (named after my current project). Then I applied the parameters and redeployed again and again until I felt confident it worked. Apparently, I felt confident after 10 redeployments.
My failure was that I didn't do any actual measuring of the state of the memory in the JVM. :clown:
Nervous sysadmin
My sysadmin contacted me today and said that he was worried that the memory usage pattern hadn't changed significantly. The JVM was still, slowly but surely, eating up all its memory. I pointet out that the MaxPermSize had been increased, and the GC probably didn't bother to reclaim memory because there was still plenty of it available. My rationale was, that once the JVM got closer to the max, it would start to do more garbage collection.
And then, I started to feel like testing my claims.
I wrote a small web application that used the MemoryMXBean to plot the NonHeap memory stats to an array list every minute, and then print the list, CSV formattet, on a JSP file. I then followed the memory usage as I start to redeploy again and a again, to see what would happen when I reached the max. As you figured, I got PermGens.
Then I snatched the memory statistics from my little plotter app, and importedd it into Excel to generate this graph:
What have we learned?
Two things:
- The PermGen issue is harder to crack than I first thought.
- One should properly test one's claims before bragging about it on blogs and dzone and whatnot.
So I guess it's back to the drawing board!


Anonymous # Thursday, March 15, 2007 8:29:50 PM
Christian Vest Hansenkarmazilla # Friday, March 16, 2007 10:18:13 AM
This is the complete bootstrap for my app server:
I saw no difference in running with and without the -server switch (other than the client uses slightly less memory).
Another thing: does the application you testet with use Hibernate?
Anonymous # Friday, March 16, 2007 12:41:37 PM
Christian Vest Hansenkarmazilla # Friday, March 16, 2007 8:57:01 PM
However, I think Hibernate is a particulary nasty framework in exposing this particular issue. I think it creates and loads new classes on the fly at run time, and thus drawing heavily on the (possibly non-heap allocated) method area of the JVMs memory space.
If you try and test again with an application that uses Hibernate in any extent, then I bet you'll see different results.
Anonymous # Friday, March 23, 2007 8:26:35 PM
Christian Vest Hansenkarmazilla # Saturday, March 24, 2007 12:02:31 PM
Read again:
"The permanent generation is used to hold reflective data 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."
The problem is, that the class and method objects properly unloaded in some cases, when you redeploy a web application on a running application server. This will slowly cause the permanent generation to fill up, and when it does, your server will die with an "OutOfMemoryError: PermGen".
The most effective way to expose the issue, that I know of, is to redeploy a web application that uses Hibernate on an application server that uses the Tomcat class loader, such as Tomcat, JBoss and Glassfish. Though I should note that I haven't actually tested on Glassfish, and they have made some changes to the class loader.
Anonymous # Wednesday, April 25, 2007 12:47:54 PM
Christian Vest Hansenkarmazilla # Wednesday, April 25, 2007 3:02:39 PM
I just tried updating to Hibernate 3.2.3.ga - still the same.
Anonymous # Thursday, April 26, 2007 3:58:11 PM
Christian Vest Hansenkarmazilla # Thursday, April 26, 2007 5:12:44 PM
So I guess the real answer is twofold:
1. Fix Tomcat if you got the time, or
2. Don't use Tomcat or any derived App Server (JBoss, Glassfish)
Someone from that post mentioned that Jetty didn't experience this issue; I'm not so sure about that. It's a while ago but I've also tried to redeploy on Jetty and as far as I recall, the memory usage had a steady growth and eventually killed the server.
EDIT:
This info might also be useful:
Only thing is figuring out how to plug Tomcat 6 into the belly of JBoss. (asuming it isn't already using it)
Anonymous # Thursday, June 7, 2007 2:13:44 PM
Christian Vest Hansenkarmazilla # Friday, June 8, 2007 6:12:35 AM
This means that using JRockit will make the problem appear to be gone, when it really isn't.
Anonymous # Wednesday, June 27, 2007 9:23:47 AM
Anonymous # Friday, February 1, 2008 3:17:43 AM
Anonymous # Wednesday, May 7, 2008 10:23:01 AM
Christian Vest Hansenkarmazilla # Wednesday, May 7, 2008 6:41:33 PM
Exactly. I believe I've also noted those blog posts here:
http://my.opera.com/karmazilla/blog/2007/09/29/return-of-the-permgen
Anonymous # Tuesday, July 28, 2009 9:10:22 AM
Anonymous # Thursday, January 7, 2010 5:24:31 AM
Anonymous # Monday, July 5, 2010 8:52:08 PM
Anonymous # Thursday, September 29, 2011 9:14:01 PM