在Tomcat中重新部署应用程序时发生内存泄漏

当我在tomcat中重新部署应用程序时,出现以下问题:

The web application [] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@10d16b]) and a value of type [com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty] (value [com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty@1a183d2]) but failed to remove it when the web application was stopped. This is very likely to create a memory leak. 

另外,我在我的应用程序中使用ehcache。 这也似乎导致以下例外。

  SEVERE: The web application [] created a ThreadLocal with key of type [null] (value [com.sun.xml.bind.v2.ClassFactory$1@24cdc7]) and a value of type [java .util.WeakHashMap... 

ehcache似乎创build了一个弱哈希映射,我得到这个消息,这很可能会造成内存泄漏。

我在网上search,发现这个, http://jira.pentaho.com/browse/PRD-3616,但我没有访问服务器。

请让我知道这些警告是否有任何function影响或可以忽略? 我在tomcatpipe理器中使用“查找内存泄漏”选项,它说“没有发现内存泄漏”

重新部署应用程序时,Tomcat会创build一个新的类加载器。 旧的类加载器必须被垃圾收集,否则你会得到一个permgen内存泄漏。

Tomcat无法检查垃圾收集是否可行,但它知道几个常见的故障点。 如果webapp类加载器为其类由webapp类加载器本身加载的实例设置了ThreadLocal ,那么servlet线程将持有对该实例的引用。 这意味着类加载器不会被垃圾回收。

Tomcat做了许多这样的检测, 在这里看到更多的信息 。 清理线程本地化是困难的,你将不得不调用remove()每个被访问的线程的ThreadLocal remove() 。 在实践中,这只在重新部署Web应用程序的过程中发挥重要作用。 在生产中,你可能不会重新部署,所以这可以被忽略。

要真正找出哪些实例定义了线程本地人,你必须使用一个分析器。 例如JProfiler中的堆栈助手(免责声明:我公司开发JProfiler)将帮助您find那些线程本地人。 select报告的值类(com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty或com.sun.xml.bind.v2.ClassFactory)并显示累积的传入引用。 其中一个将是java.lang.ThreadLocal$ThreadLocalMap$Entry 。 select该传入引用types的引用对象并切换到分配视图。 您将看到实例已分配的位置。 有了这些信息,你可以决定你是否可以做些什么。

在这里输入图像描述

Mattias Jiderhamn有一篇很好的6篇文章 ,非常清楚地解释了关于类加载器泄漏的理论和实践。 更好的是,他还发布了一个jar文件,我们可以将其包含在我们的war文件中。 我在我的networking应用程序上试过,jar文件就像一个魅力! 这个jar文件叫做classloader-leak-prevention.jar。 使用它就像将这个添加到我们的web.xml一样简单

 <listener> <listener-class>se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor</listener-class> </listener> 

然后将其添加到我们的pom.xml

 <dependency> <groupId>se.jiderhamn</groupId> <artifactId>classloader-leak-prevention</artifactId> <version>1.15.2</version> </dependency> 

有关更多信息,请参阅GitHub上托pipe的项目主页或其文章的第6部分

我猜你可能已经看到了这个,但是为了防止ehcache文档build议把这个lib放在tomcat中而不是在WEB-INF / lib中: http : //ehcache.org/documentation/integrations/tomcat

创build线程而不正确地清理它们最终会让你失去内存 – 在那里,做到了。

那些仍然想知道快速解决scheme/解决方法,可以去下面:

  • 如果运行独立的tomcat,杀死javaw.exe或承载它的进程。
  • 如果从eclipse运行,杀死eclipse.exe和java.exe或封闭进程。
  • 仍然没有解决,检查任务pipe理器,很可能是造成这一过程将显示最高的内存使用情况 – 做你的分析和杀死。

你应该很好地重新部署的东西,并继续没有内存问题。

我build议在ServletRequestListener中初始化线程本地 。

ServletRequestListener有两个方法:一个用于初始化,另一个用于销毁。

这样,你可以清理你的ThreadLocal 。 例:

 public class ContextInitiator implements ServletRequestListener { @Override public void requestInitialized(ServletRequestEvent sre) { context = new ThreadLocal<ContextThreadLocal>() { @Override protected ContextThreadLocal initialValue() { ContextThreadLocal context = new ContextThreadLocal(); return context; } }; context.get().setRequest(sre.getServletRequest()); } @Override public void requestDestroyed(ServletRequestEvent sre) { context.remove(); } } 

web.xml

 <listener> <listener-class>ContextInitiator</listener-class> </listener>