在 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 似乎创建了一个弱哈希映射,我得到的消息是这很可能会造成内存泄漏。
我在网上搜索了一下,发现了这个 http://jira.pentaho.com/browse/PRD-3616 但我没有访问服务器本身。
请告诉我这些警告是否有任何功能影响或者可以忽略吗?我在 tomcat 管理器中使用了“查找内存泄漏”选项,它显示“未发现内存泄漏”
When I redeploy my application in tomcat, I get the following issue:
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.
Also, am using ehcache in my application. This also seems to result in the following exception.
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...
The ehcache seems to create a weak hash map and I get the message that this is very likely to create a memory leak.
I searched over the net and found this,
http://jira.pentaho.com/browse/PRD-3616 but I dont have access to the server as such.
Please let me know if these warnings have any functional impact or can they be ignored? I used the "Find Memory leaks" option in tomcat manager and it says "No memory leaks found"
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
当您重新部署应用程序时,Tomcat 会创建一个新的类加载器。旧的类加载器必须进行垃圾收集,否则会出现永久内存泄漏。
Tomcat 无法检查垃圾收集是否有效,但它知道几个常见的故障点。如果 webapp 类加载器使用一个实例设置了 ThreadLocal,而该实例的类是由 webapp 类加载器本身加载的,则 servlet 线程将保存对该实例的引用。这意味着类加载器不会被垃圾回收。
Tomcat 会进行大量此类检测,请参阅此处了解更多信息。清理线程局部变量很困难,您必须在访问的每个线程中的
ThreadLocal
上调用remove()
。实际上,只有在开发过程中多次重新部署 Web 应用程序时,这一点才重要。在生产中,您可能不会重新部署,因此可以忽略这一点。要真正找出哪些实例定义了线程局部变量,您必须使用分析器。例如 JProfiler 中的堆遍历器(免责声明:我的公司开发 JProfiler)将帮助您找到那些线程局部变量。选择报告的值类(com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty 或 com.sun.xml.bind.v2.ClassFactory)并显示累积的传入引用。其中之一是
java.lang.ThreadLocal$ThreadLocalMap$Entry
。选择该传入引用类型的引用对象并切换到分配视图。您将看到实例已分配到的位置。有了这些信息,您就可以决定是否可以采取行动。When you redeploy your application, Tomcat creates a new class loader. The old class loader must be garbage collected, otherwise you get a permgen memory leak.
Tomcat cannot check if the garbage collection will work or not, but it knows about several common points of failures. If the webapp class loader sets a
ThreadLocal
with an instance whose class was loaded by the webapp class loader itself, the servlet thread holds a reference to that instance. This means that the class loader will not be garbage collected.Tomcat does a number of such detections, see here for more information. Cleaning thread locals is difficult, you would have to call
remove()
on theThreadLocal
in each of the threads that is was accessed from. In practice this is only important during development when you redeploy your web app multiple times. In production, you probably do not redeploy, so this can be ignored.To really find out which instances define the thread locals, you have to use a profiler. For example the heap walker in JProfiler (disclaimer: my company develops JProfiler) will help you to find those thread locals. Select the reported value class (com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty or com.sun.xml.bind.v2.ClassFactory) and show the cumulated incoming references. One of those will be a
java.lang.ThreadLocal$ThreadLocalMap$Entry
. Select the referenced objects for that incoming reference type and switch to the allocations view. You will see where the instance has been allocated. With that information you can decide whether you can do something about it or not.Mattias Jiderhamn 拥有出色的
6 部分文章 非常清楚地解释了有关类加载器泄漏的理论和实践。更好的是,他还发布了一个 jar 文件,我们可以将其包含在我们的 war 文件中。我在我的网络应用程序上尝试过,jar 文件非常有用!该 jar 文件名为 classloader-leak-prevention.jar。使用它非常简单,只需将其添加到我们的 web.xml 中
,然后将其添加到我们的 pom.xml 中。
有关更多信息,请参阅
托管在 GitHub 上的项目主页
或者
他的第 6 部分文章
Mattias Jiderhamn has an excellent
6-part article that explains very clearly the theory and practice about classloader leaks. Even better, he also released a jar file that we can include in our war files. I tried it on my web apps, and the jar file worked like a charm! The jar file is called classloader-leak-prevention.jar. To use it is as simple as just adding this to our web.xml
and then adding this to our pom.xml
For more information, please refer to the
project home page hosted on GitHub
or
Part 6 of his article
创建线程而不正确清理它们最终会耗尽内存 - 就在那里,这样做了。
那些仍然想知道快速解决方案/解决方法的人可以参考以下内容:
您应该很好地重新部署这些内容并继续进行,而不会出现内存问题。
Creating Threads without cleaning them up correctly will eventually run you out of memory - been there, done that.
Those who are still wondering for quick solution/workaround, can go for below:
You should be good to redeploy the stuff and proceed without memory issues.
我猜你可能看到了这个,但以防万一 ehcache 文档建议将 lib 放入 tomcat 而不是WEB-INF/lib。
I guesses you probably seen this but just in case ehcache doc recommends to put the lib in tomcat and not in WEB-INF/lib.
我建议初始化 线程本地,在 < a href="http://docs.oracle.com/javaee/7/api/javax/servlet/ServletRequestListener.html" rel="nofollow">ServletRequestListener。
ServletRequestListener
有 2 个方法:一种用于初始化,一种用于销毁。这样,您就可以清理您的
ThreadLocal
。示例:web.xml
:I recommend initializing thread locals, in a ServletRequestListener.
ServletRequestListener
has 2 methods: one for initialization and one for destruction.This way, you can cleanup your
ThreadLocal
. Example:web.xml
: