这个问题适用于曾经在 Tomcat 管理器中测试过“查找泄漏”按钮并得到如下结果的任何人:
以下 Web 应用程序已停止(重新加载、取消部署),但它们之前运行的类仍在内存中加载,从而导致内存泄漏(使用分析器确认): /leaky-app-name
我假设这与频繁重新部署时经常遇到的“永久空间”错误有关。
所以我在部署时在 jconsole 中看到的是我加载的类从大约 2k 到 5k。然后你会认为取消部署应该将它们降回 2k,但它们仍保持在 5k。
我还尝试使用以下 JVM 选项:
-XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:+CMSPermGenSweepingEnabled
我确实看到 Perm Gen 使用的空间量有很小的下降,但不是我预期的,并且加载的类数没有下降。
那么有没有一种方法可以配置 Tomcat 或设计您的应用程序以在取消部署时更好地卸载?或者我们是否在一些主要的调试会话后坚持重新启动服务器?
Tomcat 版本输出:
Server version: Apache Tomcat/6.0.29 Server built: July 19 2010 1458 Server number: 6.0.0.29 OS Name: Windows 7 OS Version: 6.1 Architecture: x86 JVM Version: 1.6.0_18-b07 JVM Vendor: Sun Microsystems Inc.
更新:
多亏了 celias 的回答,我决定做更多的挖掘工作,而且我认为由于 CXF、Spring 和 JAXB,我确定了我的应用程序中的罪魁祸首。
在我学会了如何分析 Java 应用程序后,我将分析器指向 Tomcat 并进行了一些堆转储和快照,以查看对象和类在内存中的样子。我发现在我的 CXF/JAXB (wsdl2java) 生成的类中使用的 XML 模式中的一些枚举在取消部署后仍然存在。根据我的堆转储,看起来对象被绑定到地图。免责声明:我承认我对分析和跟踪对象的调用树在 Java 中可能具有挑战性还有些陌生。
另外我应该提到我什至没有调用服务,只是部署然后取消部署它。对象本身似乎是通过部署时从 Spring 发起的反射加载的。我相信我遵循了在 Spring 中设置 CXF 服务的约定。所以我不能 100% 确定这是 Spring/CXF、JAXB 还是反射的错误。
附带说明:所讨论的应用程序是使用 Spring/CXF 的 Web 服务,而 XML 恰好是一个相当复杂的模式(NIEM的扩展)。
如果您想确保不会导致泄漏,您必须执行以下操作: