Minimalistic example
As we described above, PermGen space usage is strongly correlated with the number of classes loaded into the JVM. The following code serves as the most straightforward example:
import javassist.ClassPool; public class MicroGenerator { public static void main(String[] args) throws Exception { for (int i = 0; i < 100_000_000; i++) { generate("eu.plumbr.demo.Generated" + i); } } public static Class generate(String name) throws Exception { ClassPool pool = ClassPool.getDefault(); return pool.makeClass(name).toClass(); } }
In this example the source code iterates over a loop and generates classes at runtime. Class generation complexity is being taken care of by the javassist library.
Launching the code above will keep generating new classes and loading their definitions into Permgen space until the space is fully utilized and the java.lang.OutOfMemoryError: Permgen space is thrown.
Redeploy-time example
For a bit more complex and more realistic example, lets walk you through a java.lang.OutOfMemoryError: Permgen space error occurring during the application redeploy. When you redeploy an application, you would expect that Garbage Collection will get rid of the previous classloader referencing all the previously loaded classes and it gets replaced with a classloader loading new versions of the classes.
Unfortunately many 3rd party libraries and poor handling of resources such as threads, JDBC drivers or filesystem handles makes unloading the previously used classloader impossible. This in turn means that during each redeploy all the previous versions of your classes will still reside in PermGen generating tens of megabytes of garbage during each redeploy.
Let’s imagine an example application that connects to a relational database using JDBC drivers. When the application is started, the initializing code loads the JDBC driver to connect to the database. Corresponding to the specification, the JDBC driver registers itself with java.sql.DriverManager. This registration includes storing a reference to an instance of the driver inside a static field of DriverManager.
Now, when the application is undeployed from the application server, java.sql.DriverManager will still hold that reference. We end up having a live reference to the driver class which in turn holds reference to the instance of java.lang.Classloader used to load the application. This in turn means that the Garbage Collection Algorithms are not able to reclaim the space.
And that instance of java.lang.ClassLoader still references all classes of the application, usually occupying tens of megabytes in PermGen. Which means that it would take just a handful of redeploys to fill a typically sized PermGen and get the java.lang.OutOfMemoryError: PermGen space error message in your logs.