Friday, 22 July 2011

java.lang.OutOfMemoryError: PermGen

Like most people, I’ve experienced the pain of a java.lang.OutOfMemoryError: PermGen exception when developing applications using a Weblogic server. It usually occurs when I’m running my Weblogic server with Sun’s Hotspot JVM and, like most people I’ve complained that the developers at Oracle should fix this problem, but the question is, can they?

The short answer is no, as the problem is caused by a memory leak somewhere in your application. In order to explain what’s happening, the first thing to do is to briefly explain what permGen space is.

Gen or generation space is all to do with heap space. There are three types of generation space: new gen, old gen and perm gen. Now, very simplistically, objects comprise of code that runs plus their data. So, when you deploy your application, your classes are loaded by their classloader(s) the code (i.e. the stuff that runs plus class meta data) is loaded into perm gen space, whilst its data is stuck into new gen space.

Just sticking with the new and old gen thing for one moment, I think that the idea here is that new gen is garbage collected often, and hence transient objects are stored here. If, after a certain number of passes of the GC the object is still in use, then it’s moved to old gen, which is GC’ed less often.

When you undeploy your application, your classloader and all the classes it loaded are marked for garbage collection. That’s the theory anyway... however, if something holds on to a class reference or references (i.e. the memory leak), then those classes aren’t marked for garbage collection and are left discarded by the container but still in memory. You then redeploy your application taking up more perm gen space and after a few deploys and undeploys, then you get the java.lang.OutOfMemoryError: PermGen exception.

The 'fix', or work around, to the problem is to increase your server's perm gen space and this is done by using the following compiler argument:

-XX:MaxPermSize=128m

The default value is 64m or 64MB. Sun, and now Oracle, document all this on their website

Finally, you can try using the JRocket JVM, it’s a different kettle of fish to the Sun Hotspot JVM, but at the end of the day, you’ll just have to either find your memory leak or restart the server.

5 comments:

Adam Perry said...

This happens a lot on Tomcat and especially when we used Drools- everytime you reload/redeploy the web app.

One solution in Tomcat- you can specify a shell file to run when the server has run out of memory. Which can be a 'restart' script. Not ideal but better than a server going down!

Philippe said...

That's not a VM bug. That's "just" a memory leak. Fix the leak and you can redeploy as often as you want. The leak does not have to be in your code, it could also be in a library or the container. The very latest Tomcat 6 and 7 versions help a lot.

You might find the following links of interest
Tomcat Wiki MemoryLeakProtection
Tomcat Wiki OutOfMemory

Roger Hughes said...

Philippe, thanks for the useful links.

Stefan said...

Here is another useful link: http://frankkieviet.blogspot.de/2006/10/classloader-leaks-dreaded-permgen-space.html

Unknown said...

Permgen out of memory happens a lot on a Continuos Integration and deployment environment ie. Jenkins under tomcat.

Each redeploy slowly leaks since the Classloaders are not GC'd

A clean restart periodically seems the only solution, I hope the move to Java 8 (Permgen absorbed to the Heap) may help, though Im sure it will leak there too.