在tomcat中重新部署应用程序时的java内存泄漏

slwdgvem  于 2021-06-02  发布在  Hadoop
关注(0)|答案(5)|浏览(521)

在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似乎创建了一个弱哈希Map,我得到的消息是,这很可能会造成内存泄漏。
我在网上搜索发现了这个,http://jira.pentaho.com/browse/prd-3616 但是我没有访问服务器的权限。
请让我知道这些警告是否有任何功能影响或可以忽略?我在tomcat管理器中使用了“find memory leaks”选项,它说“no memory leaks found”

sz81bmfz

sz81bmfz1#

创建线程而不正确地清理它们,最终会耗尽内存——一直在那里,就这样做了。
那些仍然想快速解决/解决方法的人可以选择以下方法:
如果运行独立的tomcat,请杀死javaw.exe或承载它的进程。
如果从eclipse运行,请终止eclipse.exe和java.exe或封闭进程。
仍然没有解决,检查任务管理器,很可能导致此问题的进程将以最高的内存使用率显示-进行分析并杀死它。
你应该很好地重新部署的东西,继续没有内存问题。

xienkqul

xienkqul2#

mattias jiderhamn有一篇出色的6部分文章,非常清楚地解释了classloader泄漏的理论和实践。更妙的是,他还发布了一个jar文件,我们可以将其包含在war文件中。我在我的网络应用程序上试过了,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上的项目主页或其文章的第6部分

kognpnkq

kognpnkq3#

我建议在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` :
bd1hkmkf

bd1hkmkf4#

重新部署应用程序时,tomcat会创建一个新的类装入器。旧的类加载器必须被垃圾收集,否则会导致永久内存泄漏。
tomcat无法检查垃圾收集是否可以工作,但是它知道一些常见的失败点。如果webapp类加载器设置 ThreadLocal 对于其类由webapp类装入器本身装入的示例,servlet线程持有对该示例的引用。这意味着类装入器不会被垃圾收集。
tomcat做了很多这样的检测,更多信息请参见这里。清理线程是困难的,你必须打电话 remove()ThreadLocal 在从中访问的每个线程中。实际上,只有在开发过程中多次重新部署web应用时,这才是重要的。在生产中,您可能不会重新部署,因此可以忽略这一点。
要真正找出哪些示例定义了线程局部变量,必须使用探查器。例如,jprofiler中的heap walker(免责声明:我的公司开发了jprofiler)将帮助您找到这些线程局部变量。选择报告的值类(com.sun.xml.bind.v2.runtime.property.singleelementleafproperty或com.sun.xml.bind.v2.classfactory)并显示累积的传入引用。其中一个将是 java.lang.ThreadLocal$ThreadLocalMap$Entry . 为传入的引用类型选择引用对象,并切换到“分配”视图。您将看到示例已分配到何处。有了这些信息,你就可以决定你是否能做些什么。

fdx2calv

fdx2calv5#

我猜您可能看到了这一点,但以防万一ehcache doc建议将lib放在tomcat中,而不是放在webinf/lib中。

相关问题