有没有办法避免Tomcat中的部署内存泄漏?

时间:2010-12-30 18:14:49

标签: java spring tomcat memory-leaks jaxb

这个问题适用于曾经测试过Tomcat管理器中“查找泄漏”按钮的人,并得到了一些结果:

  

以下Web应用程序已停止(重新加载,取消部署),但之前运行的类仍然在内存中加载,从而导致内存泄漏(使用分析器确认):
  /漏应用名称

我认为这与经常重新部署经常会遇到的“Perm Gen space”错误有关。

所以我在部署时在jconsole中看到的是我的加载类从大约2k到5k。然后你会认为取消部署应该将它们降低到2k,但它们仍然保持在5k。

我也尝试使用以下JVM选项:

-XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:+CMSPermGenSweepingEnabled

我确实看到Perm Gen空间的使用量非常小,但不是我预期的,并且加载的类数没有下降。

那么有没有办法配置Tomcat或设计你的应用程序以便在取消部署时更好地卸载?或者我们是否在一些重要的调试会话后重新启动服务器?

Tomcat版本输出:

  

服务器版本:Apache Tomcat / 6.0.29
  服务器内置:2010年7月19日1458
  服务器编号:6.0.0.29
  操作系统名称:Windows 7
  操作系统版本:6.1
  架构:x86
  JVM版本:1.6.0_18-b07
  JVM供应商:Sun Microsystems Inc.

更新

感谢celias的回答,我决定多做一些挖掘,我认为由于CXF,Spring和JAXB,我确定了应用程序的罪魁祸首。

在我学会了如何分析Java应用程序之后,我将分析器指向Tomcat并获取了一些堆转储和快照,以查看对象和类在内存中的外观。我发现在我的CXF / JAXB(wsdl2java)生成的类中使用的XML模式中的一些枚举在取消部署后仍然存在。根据我的堆转储,它看起来像是绑定到Map。免责声明:我承认我仍然是一个绿色的分析和跟踪对象的调用树在Java中可能具有挑战性。

另外我应该提一下,我甚至没有调用该服务,只是部署然后取消部署它。对象本身似乎是通过部署时从Spring发起的反射加载的。我相信我遵循了在Spring中设置CXF服务的惯例。所以我不能100%确定这是Spring / CXF,JAXB还是反射的错误。

作为旁注:有问题的应用程序是使用Spring / CXF的Web服务,而XML恰好是一个相当复杂的模式(NIEM的扩展)。

2 个答案:

答案 0 :(得分:15)

如果您想确保不泄漏,您必须执行以下操作:

  • 确保您的Web应用程序不使用Web容器共享库中的任何Java类。如果您有任何共享库,请确保没有对这些库中对象的强引用
  • 避免使用静态变量,特别是对于HashTable,Sets等Java对象。如果需要,请确保调用remove以使用地图,列表释放对象...

这里还有关于ThreadLocal和MemoryLeaks的好文章 - http://blog.arendsen.net/index.php/2005/02/22/threadlocals-and-memory-leaks-revisited/

答案 1 :(得分:6)

Tomcat 7应该会在这方面带来改进。请参阅Features of Apache Tomcat 7,标题为 No More Leaks!

的部分

他们相信他们现在可以应对Web应用程序导致的大量内存泄漏。不幸的是,它仍处于测试阶段。

除此之外,我可以说我已经取得了相同的经验并且没有找到解决方案。部署通常需要在之后重新启动Tomcat。我不知道罪魁祸首是谁:我的网络应用程序,Tomcat,Hibernate,Tapestry或其中几个。