为了确定重新部署是否产生内存泄漏(垃圾收集清除不干净,消耗内存越来越多),一个有效的检查方法就是undeploy后,容器为Web Application创建的class loader应该会消失,如果没有的话,那就肯定有内存泄漏了,这时还可以用Profiler工具查看是哪些对象仍然被引用了,比如下图:
容器用的是Jetty,重新部署三次后undeploy,仍然能看到三个WebAppClassLoader对象,每个对象都是因为有org.dom4j.DocumentFactory对象被引用了,引用者就是一个ThreadLocal对象并绑定到了容器创建的一个定时服务线程上(所以不能释放掉)。Dom4J是一个比较好用的XML解析器,估计也是用ThreadLocal来做cache提高性能,搜索一下dom4j memory leak,还真有人报告过这个问题。解决的方法则是升级Dom4J到1.6.1以上,新版本已经解决了这个问题。。。
下面的图是解决内存泄漏后的一次重新部署,可以清楚看到垃圾收集启动了一次,清除干净了内存,WebAppClassLoader对象还是只有一个。
常见的造成内存泄漏的原因:
JDBC Driver Manager
在全局的DriverManager注册了 driver后不注销掉会引起内存泄漏,解决方法是在ServletContextListener的contextDestroyed()方法内使用下列代码:
try {
Enumeration drivers = DriverManager.getDrivers();
while(drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
if (driver.getClass().getClassLoader() == getClass().getClassLoader()) {
DriverManager.deregisterDriver(driver);
}
}
} catch (SQLException e) {
e.printStackTrace();
}
Hibernate
Hibernate 3用的cglib也有ThreadLocal内存泄漏,升级到3.2.5以后才修正了这个问题。



My name is Hugo Zhu.



