开发时候为了提高效率,我们总希望重新编译的类能立刻生效,或重新部署应用而不重新启动应用服务器—所谓的”热部署“
无论是用Resin, Tomcat,Jetty, 如果你试图不重新启动应用服务器,而重新部署你的应用(WebApp),多来几次后就可能会出现:”java.lang.OutOfMemoryError: PermGen space”的错误。
PermGen 是JVM用来保存类定义和常量池的保留空间,缺省是64M,虽然你可以通过 -XX:MaxPermSize启动参数来增加PermGen空间,但这也只是允许你多reload几次,而不能根本解决问题。
问题主要原因是出在Class loader上,Tomcat是按下面的关系来创建Webapp的Class Loader(详见:http://tomcat.apache.org/tomcat-6.0-doc/class-loader-howto.html)
Bootstrap
|
System
|
Common
/ \
Webapp1 Webapp2 ...
通过这种方式,应用服务器可以把不同的Webapp严格区分开来,Webapp1中载入的class在Webapp2可以不可见,但在System或Common里载入的则都可见,实际应用中,Tomcat或Resin的lib目录下jar库可以被所有webapp调用。
当你重新部署一个应用时候,容器一般是把原来供这个Webapp的class loader设成null,并为应用重新创建一个class loader来装载应用使用的类。理想情况下当然是希望之前的class loader能够完全被垃圾收集。但实际情况下如果你的应用使用了别的class loader(如System),对象被上层class loader引用后不能被释放,那应用的class loader就不能干净地被垃圾收集了。例如下面的代码:
private static final ThreadLocal cache = new ThreadLocal();
cache.set(yourObject);
因为ThreadLocal对象绑定在当前线程,而该线程由应用服务器本身创建(使用了更高层的Class Loader),原来的应用就再也不能被垃圾收集干净了。
My name is Hugo Zhu.




Conclusion: Any reference from outside the application to an object in the application of which the class is loaded by the application’s classloader will cause a classloader leak.