Class loader leaks:the dreaded“java.lang.OutOfMemoryError:PermGen space”excep


テキスト
http://blogs.sun.com/fkieviet/entry/classloader_leaks_the_dreaded_java
Class loader leaks:the dreaded“java.lang.OutOfMemoryError:PermGen space”exception
Did you ever encounter a java.lang.OutOf MemoryError:PermGen space error when you reployed your appication to an appration server?Did you curse the appration server,while restating the appration server,to conting with your work thinking that is is clearly a bug in the appration server.Those appication server.server developer the ulgeirt,theWell,perhaps.But perhaps it's really  your fault
Take a look the follwing example of an innocent look servlet.
package com.stc.test;

import java.io.*;
import java.util.logging.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class MyServlet extends HttpServlet {
 protected void doGet(HttpServletRequest request, HttpServletResponse response)
 throws ServletException, IOException {
 // Log at a custom level
 Level customLevel = new Level("OOPS", 555) {};
 Logger.getLogger("test").log(customLevel, "doGet() called");
 }
}
Try to redeploy this little sample a number of times.  I bet this will eventualy fail with the dreaded java.lang.OutOf MemoryError:PermGen space error.If you like to unders what's happening、read on.
The problem in a nutshell
Application servers such as Glassfish allow you to write an aplication(.ear,war,etc)and deploy appication with other appication on.Shoud feel the need make a change theurication,your the copuricationand redeploy the aplication without affecting the other still running appination in in the appication server:you don't need to the application server.This mechange works fine on Glassfish and the appration
The way that this works s s isaaat aaaaaaapaication is loaded using its own classiloader.Simply put、a clasloader isa special clasthaaaaaaaaaaaaaaaaaat loads.clasfiles files files.When unundeploy thethethethetheaapapadidididididicacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaca...
Somehow,something may hold on to the classiloader however,and prevent it from being garbage colleced.And that's what's causing the java.lang.OutOfMemoryErr:PermGen space exception.
PermGen space
What is PermGen space anyways?The memory in the Virtual Machine is divided in to a number of region s.One of these regions is PermGen.It's and ara of memory that is used to(among other things)load class files.The size of this memoris.i.e.it does not change when the VM is running.You can specify the size of this region with a commandine switch:-XX:MaxPermSize.The default is 64 Mb on the Sun VMs.
If there's a problem with garbage colecting clases and if Youkeep loading new clases、the VM will run out of space e e e e e e memomomoregion、evn if there's plenty of memomoryavmorilable on the heaaaaathe.Settininininstststststststheheheheheheheheheheheheheheheheststststststststststststststststststststststststininine e e e e e e e e e e e e e e e e e e e e e e e e e e e thethethethethethethethethethethethethethe size of the PermGen region.
Garbage collecting and classloaders
When you write something silly like
private void x1() {
        for (;;) {
            List c = new ArrayList();
        }
    }
you're continuously allocating object;yet the program doesn't run out of memory:the object s that create are garbage colleced thereby freeing up space so that can allocate another oject.An oject can only be garbage collect theobleWhat this is means s s is that there is no way to access the object from anywhere in the program.If nobody can access the oject,there'sのpoint in keeping the oject,so it gets garbage collcted.Let.Let's thetherererererererererethethethethethethethethethethethethethethethethethetheaaaaaaaaaathethethethethethethethethererererererererererererererererererererererererererererererererererererererererererereeeee
package comp.stc.test;
import java.io.*;
import java.net.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class Servlet 1 extens HttpServlet{
prvate static final String STATICNAME="Simple"
protected void doGet(HttpServlet Request request、HttpServlet Resonse)
throws Servlet Exception、IOException{
)
)
After loading the above servlet,the follwing object are in memory(offurse limited to the relevantons):
Classloader leaks: the dreaded "java.lang.OutOfMemoryError: PermGen space" excep
In this picture you see the object by the appration class loader in yellow,and the ret in green.You see a simplified container oject that hold references to the appliationmethod on it when a web request corees in.Note that the STATICNE oject is owned by the class oject.Other import things to notice:
Like each object,the Servlet 1 instance holds a reference to its class(Servlet.class)
Each class object(e.g.Servlet 1.class)holds a reference to the class loader that loaded it.
Each classiloader holds references to all the classis that it loaded.
The importent consequence of this that whenever an object out side of Apple Class loader holds a reference to an object loaded by Ap Class loader、none of the clases can be garbage collected.
To illustrate this、let's see what happens when the appration gets undeployed:the Continer oject nullifies its references to the Servlet 1 instance and to the ApClass loader ject.
Classloader leaks: the dreaded "java.lang.OutOfMemoryError: PermGen space" excep
As You can see,none of the object s are reachable,so they all can be garbage colleced.Now let's see whappens when we the original example where the Level class:package.collect;
import java.io.*;
import java.net.*;
import java.util.logging.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class LeakServlet extends HttpServlet {
 private static final String STATICNAME = "This leaks!";
 private static final Level CUSTOMLEVEL = new Level("test", 550) {}; // anon class!

 protected void doGet(HttpServletRequest request, HttpServletResponse response)
 throws ServletException, IOException {
 Logger.getLogger("test").log(CUSTOMLEVEL, "doGet called");
 }
}
Note that the CUSTOMLEVEL's class is anonymous class.That is necessary because the constructor of Level is protected.Let's take a looka the memory picture of this scenaro:
Classloader leaks: the dreaded "java.lang.OutOfMemoryError: PermGen space" excep
In this picture you see something you may not have expected:the Level class holds a static member to all Level oject s that were created.Here's the constructor of the Level class the JK:
protected Level(String name, int value) {
 this.name = name;
 this.value = value;
 synchronized (Level.class) {
 known.add(this);
 }
 }
Here known is a static ArayList in the Level class.Now what happens if the appication is undeployed?
Classloader leaks: the dreaded "java.lang.OutOfMemoryError: PermGen space" excep
Only the Leak Servlet object can be garbage colleced.Because of the reference to the CUSTOMLEVEL oject from of Apple loader,the  CUSTOMLEVL anyonymous class object caak Servlet$1.lass)cannot be garbage collected、and through neither can the ApClass loader、and hence none of the classist the ApClanter
Concection:any reference from outside the appration to an object in the appication of which the class is loaded by the appration's classloader will cause a classider leak.
More sneaky problems
I don't blame you ifyou didn't see the problem with the Level clas:it's s s neaky.Last year we had some undeployment problems inapaplication server.My team,in particular Edward Chou,spentthethethethethethethethethethethethethethethethethethetheme proproproproproprottttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttinstance,if you happen to use some of the Apache Commons BeanHelper's code:there's a static cache in in that code that refers to Method object.The Method object holds a reference to the class the the Method poinfont.atmont.atmont.appect.you do have a problem if this code is also present in the classity of the appication server because those classies.As a receedence now and have references to clases in your appration from the appication the the appration class.classicars.classerclassears's.ors.ors.sears.ors.ors.ors.ors.As.As.
I did not mentiond yet the simplest recipe for disaster:a thread started by the appration while the thread does ext after the appration is undeployed.
Detection and solution
Class loader leak s are difficult.Detecting if there's such a leak without having to deploy/undeploy a large number of times difficult.Finding the source of a classider leak is the tricerdid not follows links through classide loaders.The refore we rerested to writing some custom code to find the leaks from memory dump files.Since that exercise,new tools came to market JDK 6.The blog the the proadext holdration profilt profilect profiless day