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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4565105/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 06:59:32  来源:igfitidea点击:

Is there a way to avoid undeployment memory leaks in Tomcat?

javaspringtomcatmemory-leaksjaxb

提问by waltwood

This question is for anyone who's ever tested the "Find leaks" button in the Tomcat manager and got some results like this:

这个问题适用于任何曾经在 Tomcat 管理器中测试过“查找泄漏”按钮并得到如下结果的人:

The following web applications were stopped (reloaded, undeployed), but their classes from previous runs are still loaded in memory, thus causing a memory leak (use a profiler to confirm):
/leaky-app-name

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

I'm assuming this has something to do with that "Perm Gen space" error you often get with frequent redeployments.

我假设这与频繁重新部署时经常遇到的“永久空间”错误有关。

So what I'm seeing in jconsole when I deploy is that my loaded classes goes from about 2k to 5k. Then you would think an undeployment should drop them back down to 2k but they remain at 5k.

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

I've also tried using the following JVM options:

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

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

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

I did see VERY minor dips in the amount of Perm Gen space used but not what I expected and the loaded class counts did not drop.

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

So is there a way to configure Tomcat or design your app to unload better on an undeployment? Or are we stuck with restarting the server after some major debugging sessions?

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

Tomcat version output:

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.

服务器版本: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.

Update:

更新:

Thanks to celias' answer I decided to do a little more digging and I think I determined the culprit to be in my application thanks to CXF, Spring and JAXB.

多亏了 celias 的回答,我决定做更多的挖掘工作,而且我认为由于 CXF、Spring 和 JAXB,我确定了我的应用程序中的罪魁祸首。

After I learned how to profile a Java application, I pointed the profiler at Tomcat and took some heap dumps and snapshots to see what the objects and classes looked like in memory. I discovered that some of the enumerations from my XML schema used in my CXF/JAXB (wsdl2java) generated classes were lingering after an undeployment. According to my heap dump it looks like the objects were tied to a Map. Disclaimer: I admit I'm still a little green with profiling and tracing an object's call tree can be challenging in Java.

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

Also I should mention that I didn't even invoke the service, just deployed then undeployed it. The objects themselves appeared to be loaded via reflection initiated from Spring on deployment. I believe I followed the convention for setting up a CXF service in Spring. So I'm not 100% sure if this is Spring/CXF, JAXB, or reflection's fault.

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

As a side note: the application in question is a web service using Spring/CXF and the XML happens to be a rather complex schema (an extension of NIEM).

附带说明:所讨论的应用程序是使用 Spring/CXF 的 Web 服务,而 XML 恰好是一个相当复杂的模式(NIEM的扩展)。

采纳答案by celias

If you want to make sure not to cause leaks you have to do the following:

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

  • Make sure your web application does not use any java classes that are in the web container shared libraries. If you have any shared libraries, make sure there is no strong references to the objects in those libraries
  • Avoid using static variables, especially on java objects like HashTable, Sets, etc. If you need to, make sure that you call remove to release the objects with the maps, lists...
  • 确保您的 Web 应用程序不使用 Web 容器共享库中的任何 Java 类。如果您有任何共享库,请确保没有对这些库中的对象的强引用
  • 避免使用静态变量,尤其是在 HashTable、Sets 等 java 对象上。如果需要,请确保调用 remove 以释放带有映射、列表的对象...

Here is also a good article on ThreadLocal and MemoryLeaks - http://blog.arendsen.net/index.php/2005/02/22/threadlocals-and-memory-leaks-revisited/

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

回答by Codo

Tomcat 7 is supposed to bring improvements in this area. See Features of Apache Tomcat 7, section titled No More Leaks!

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

They believe they can now cope with a lot of memory leaks caused by the web applications. Unfortunately, it's still in beta.

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

Other than that, I can just say that I've made the same experience and haven't found a solution. Deploying usually requires restarting Tomcat afterwards. I have no idea who the culprit is: my web application, Tomcat, Hibernate, Tapestry or several of them.

除此之外,我只能说我有过同样的经历,但还没有找到解决方案。部署通常需要在之后重新启动 Tomcat。我不知道罪魁祸首是谁:我的 Web 应用程序、Tomcat、Hibernate、Tapestry 或其中几个。