小编典典

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

go

这个问题适用于曾经在 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的扩展)。


阅读 172

收藏
2021-12-10

共1个答案

小编典典

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

  • 确保您的 Web 应用程序不使用 Web 容器共享库中的任何 Java 类。如果您有任何共享库,请确保没有对这些库中的对象的强引用
  • 避免使用静态变量,尤其是在 HashTable、Sets 等 java 对象上。如果需要,请确保调用 remove 以释放带有映射、列表的对象…
2021-12-10