有没有办法避免Tomcat中的卸载内存泄漏?
此问题适用于曾经在 Tomcat 管理器中测试过查找泄漏"按钮并得到如下结果的任何人:
This question is for anyone who's ever tested the "Find leaks" button in the Tomcat manager and got some results like this:
以下 Web 应用程序已停止(重新加载、取消部署),但它们之前运行的类仍加载到内存中,从而导致内存泄漏(使用分析器确认):
/leaky-app-name
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
我假设这与频繁重新部署时经常遇到的Perm Gen space"错误有关.
I'm assuming this has something to do with that "Perm Gen space" error you often get with frequent redeployments.
所以我在部署时在 jconsole 中看到的是我加载的类从大约 2k 变为 5k.然后您会认为取消部署应该将它们降回 2k,但它们仍保持在 5k.
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.
我也尝试过使用以下 JVM 选项:
I've also tried using the following JVM options:
-XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:+CMSPermGenSweepingEnabled
我确实看到 Perm Gen 空间使用量有非常小的下降,但不是我预期的,加载的类数也没有下降.
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.
那么有没有办法配置 Tomcat 或设计您的应用程序以在取消部署时更好地卸载?或者在一些主要的调试会话之后我们是否坚持重新启动服务器?
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:
服务器版本: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.
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.
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.
在我学会了如何分析 Java 应用程序后,我将分析器指向 Tomcat,并拍摄了一些堆转储和快照,以查看对象和类在内存中的样子.我发现在我的 CXF/JAXB (wsdl2java) 生成的类中使用的 XML 模式中的一些枚举在取消部署后仍然存在.根据我的堆转储,看起来对象绑定到了地图.免责声明:我承认我对分析和跟踪对象的调用树在 Java 中可能具有挑战性.
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.
另外我应该提到我什至没有调用服务,只是部署然后取消部署它.对象本身似乎是通过部署时从 Spring 启动的反射加载的.我相信我遵循了在 Spring 中设置 CXF 服务的约定.所以我不能 100% 确定这是 Spring/CXF、JAXB 还是反射的错误.
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/CXF 的 Web 服务,而 XML 恰好是一个相当复杂的模式(NIEM).
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).
推荐答案
如果你想确保不会导致泄漏,你必须执行以下操作:
If you want to make sure not to cause leaks you have to do the following:
- 确保您的 Web 应用程序不使用 Web 容器共享库中的任何 Java 类.如果您有任何共享库,请确保这些库中的对象没有强引用
- 避免使用静态变量,尤其是在 HashTable、Sets 等 java 对象上.如果需要,请确保调用 remove 以释放带有映射、列表的对象...
这里还有一篇关于 ThreadLocal 和 MemoryLeaks 的好文章 - http://blog.arendsen.net/index.php/2005/02/22/threadlocals-and-memory-leaks-revisited/
Here is also a good article on ThreadLocal and MemoryLeaks - http://blog.arendsen.net/index.php/2005/02/22/threadlocals-and-memory-leaks-revisited/
相关文章