Tuesday, March 12, 2013

HotSpot—java.lang.OutOfMemoryError: PermGen space

There could be different causes that lead to out-of-memory error in HotSpot VM.  For example, you can run out of memory in PermGen space:
  • java.lang.OutOfMemoryError: PermGen space

In this article, we will discuss:
  • Java Objects vs Java Classes
  • PermGen Collection[2]
  • Class unloading
  • How to find the classes allocated in PermGen?
  • How to enable class unloading for CMS?
Note that this article is mainly based on Jon's excellent article[1].

Java Objects vs Java Classes


Java objects are instantiations of Java classes. HotSpot VM has an internal representation of those Java objects and those internal representations are stored in the heap (in the young generation or the old generation[2]). HotSpot VM also has an internal representation of the Java classes and those are stored in the permanent generation.

PermGen Collector


The internal representation of a Java object and an internal representation of a Java class are very similar.  From now on, we use Java objects and Java classes to refer to their internal representations.  The Java objects and Java classes are similar to the extent that during a garbage collection both are viewed just as objects and are collected in exactly the same way.

Besides its basic fields, Java class also include the following:
  • Methods of a class (including the bytecodes)
  • Names of the classes (in the form of an object that points to a string also in the permanent generation)
  • Constant pool information (data read from the class file, see chapter 4 of the JVM specification for all the details).
  • Object arrays and type arrays associated with a class (e.g., an object array containing references to methods).
  • Internal objects created by the JVM (java/lang/Object or java/lang/exception for instance)
  • Information used for optimization by the compilers (JITs)
There are a few other bits of information that end up in the permanent generation but nothing of consequence in terms of size. All these are allocated in the permanent generation and stay in the permanent generation.

Class Loading/Unloading


Back in old days, most classes were mostly static and custom class loaders were rarely used.  Then class unloading may not be necessary.  However, things have changed and sometimes you could run into the following message:
  • java.lang.OutOfMemoryError: PermGen space
In this case, there are at least two options:
  • Increasing the size of PermGen
  • Enabling class unloading

Increasing the Size of PermGen


Sometimes there is a legitimate need to increase PermGen size by setting the following options:
  • -XX:PermSize=384m -XX:MaxPermSize=384m 
However, before you do that, you may want to find out what Java classes were allocated in PermGen by running
  • jmap -permstat
This is supported in JDK5 and later on both Solaris and Linux.

Enabling Class Unloading


By default, most HosSpot Garbage Collectors do class unloading except CMS collector[2] (enabled by  -XX:+UseConcMarkSweepGC).

If you use CMS collector and run into PermGen's out-of-memory error, you could consider enabling class unloading by setting:
  • -XX:+CMSClassUnloadingEnabled
  • -XX:+CMSPermGenSweepingEnabled

Depending on the release you may have, earlier versions (i.e.,  Java 6 Update 3 or earlier) require you to set both options.  However, in later releases you only need to specify:
  • -XX:+CMSClassUnloadingEnabled

The following are the cases that you want to enable class unloading in CMS collectors:
  • If your application is using multiple class loaders and/or reflection, you may need to enable collecting of garbage in permanent space.
  • Objects in permanent space may have references to normal old space thus even if permanent space is not full itself, references from perm to old space may keep some dead objects unreachable for CMS if class unloading is not enabled.
  • Lots of redeployment may pressure PermGen space
    • A class and it's classloader have to both be unreachable in order for them to be unloaded. A class X with classloader A and the same class X with classloader B will result in two distinct objects (klassses) in the permanent generation. 

References

  1. Understanding GC pauses in JVM, HotSpot's CMS collector.
  2. Understanding Garbage Collection
  3. Presenting the Permanent Generation
  4. Diagnosing Java.lang.OutOfMemoryError
  5. A Case Study of java.lang.OutOfMemoryError: GC overhead limit exceeded
  6. Understanding Garbage Collector Output of Hotspot VM
  7. Java HotSpot VM Options

No comments: