最近在用eclipse调试一个老项目,server用的tomcat5.5, reload了几次应用就报错,方法区溢出:
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space。
用visualvm查看heap dump,发现项目中的第三方jar包的类都被重新加载了好几次,最后方法区空间不足,一直进行fullgc,却无法回收重复的类。![]()
用tomcat7相同环境下运行正常,reload几次后,方法区空间不足时,会回收所有原先WebappClassLoader重复加载的类,
。
2个tomcat jvm运行模式和参数都一致,都是使用默认的垃圾回收机制,后来tomcat5.5试着用了CMS垃圾收集器还是报原先的错误:
应该是tomcat5.5 reload代码实现有问题
用tomcat7相同环境下运行正常,reload几次后,方法区空间不足时,会回收所有原先WebappClassLoader重复加载的类,
2个tomcat jvm运行模式和参数都一致,都是使用默认的垃圾回收机制,后来tomcat5.5试着用了CMS垃圾收集器还是报原先的错误:
-XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
应该是tomcat5.5 reload代码实现有问题
tomcat7的reload源码,应该tomcat7在reload时清理引用做了写改进吧,WebappClassLoader处理内存泄露 clearReferences():
/**
* Clear references.
*/
protected void clearReferences() {
// De-register any remaining JDBC drivers
clearReferencesJdbc();
// Stop any threads the web application started
clearReferencesThreads();
// Check for leaks triggered by ThreadLocals loaded by this class loader
checkThreadLocalsForLeaks();
// Clear RMI Targets loaded by this class loader
clearReferencesRmiTargets();
// Null out any static or final fields from loaded classes,
// as a workaround for apparent garbage collection bugs
if (clearReferencesStatic) {
clearReferencesStaticFinal();
}
// Clear the IntrospectionUtils cache.
IntrospectionUtils.clear();
// Clear the classloader reference in common-logging
if (clearReferencesLogFactoryRelease) {
org.apache.juli.logging.LogFactory.release(this);
}
// Clear the resource bundle cache
// This shouldn't be necessary, the cache uses weak references but
// it has caused leaks. Oddly, using the leak detection code in
// standard host allows the class loader to be GC'd. This has been seen
// on Sun but not IBM JREs. Maybe a bug in Sun's GC impl?
clearReferencesResourceBundles();
// Clear the classloader reference in the VM's bean introspector
java.beans.Introspector.flushCaches();
}
查了相关的资料:
一般程序库可能存在内存泄漏的地方有:
1.JDBC驱动注册
2.一些日志框架
3.在ThreadLocal中保存对象,但是并不去删除它
4.启动了线程,但没有停止它
而Java API存在内存泄漏的地方包括:
1.使用javax.imageio API (the Google Web Toolkit can trigger this)
2.使用java.beans.Introspector.flushCaches() (Tomcat does this to prevent memory leaks caused by this caching)
3.使用XML解析器(the root cause is unknown due to a bug in the JRE)
4.使用RMI远程方法调用(somewhat ironically, causes a leak related to the garbage collector)
5.从Jar文件中读取资源