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

时间:2022-09-05 18:51:26

When I redeploy my application in tomcat, I get the following issue:

当我在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.

Also, am using ehcache in my application. This also seems to result in the following exception.

另外,在我的应用程序中使用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... 

The ehcache seems to create a weak hash map and I get the message that this is very likely to create a memory leak.

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

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.

我在网上搜索找到了这个,http://jira.pentaho.com/browse/PRD-3616,但是我没有访问服务器的权限。

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"

请让我知道这些警告是否有任何功能影响,或者它们是否可以被忽略?我在tomcat manager中使用了“查找内存泄漏”选项,它说“没有发现内存泄漏”

5 个解决方案

#1


36  

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将创建一个新的类装入器。旧的类装入器必须是垃圾收集,否则就会出现permgen内存泄漏。

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无法检查垃圾收集是否有效,但是它知道几个常见的故障点。如果webapp类加载器设置了一个ThreadLocal,该实例的类被webapp类加载器加载,那么servlet线程将引用该实例。这意味着类装入器不会被垃圾收集。

Tomcat does a number of such detections, see here for more information. Cleaning thread locals is difficult, you would have to call remove() on the ThreadLocal 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.

Tomcat做了许多这样的探测,在这里查看更多的信息。清理线程局部是困难的,您必须在每个被访问的线程中调用remove()。实际上,当您多次重新部署web应用程序时,这是非常重要的。在生产中,您可能不会重新部署,因此可以忽略这一点。

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.

要真正发现哪些实例定义了线程局部变量,必须使用分析器。例如JProfiler中的heap walker(声明:我的公司开发JProfiler)将帮助您找到这些线程本地。选择所报告的值类(com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty或com.sun.xml.bind.v2.ClassFactory),并显示已添加的传入引用。其中一个将是java.lang.ThreadLocal$ThreadLocalMap$Entry。为该传入引用类型选择引用对象,并切换到分配视图。您将看到实例的分配位置。有了这些信息,你就可以决定你是否能做些什么。

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

#2


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

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

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

and then adding this to our pom.xml

然后将它添加到我们的pom.xml中。

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

For more information, please refer to the project home page hosted on GitHub or Part 6 of his article

有关更多信息,请参考GitHub上的项目主页或他文章的第6部分。

#3


3  

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:

那些仍在为快速解决方案而犹豫不决的人,可以选择以下几点:

  • If running the standalone tomcat, kill javaw.exe or the process bearing it.
  • 如果运行独立的tomcat,则杀死javaw。exe或轴承的过程。
  • If running from eclipse, kill eclipse.exe and java.exe or enclosing process.
  • 如果在eclipse中运行,可以杀死eclipse。exe和java。exe或封闭的过程。
  • Still not resolved, Check for the task manager, it is likely that the process which is causing this will be shown with highest memory usage - Do your analysis and kill that.
  • 仍然没有解决,检查任务管理器,可能导致这一过程的过程将显示为最高的内存使用——做您的分析并杀死它。

You should be good to redeploy the stuff and proceed without memory issues.

您应该很好地重新部署这些内容,并且不需要内存问题。

#4


2  

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: http://ehcache.org/documentation/integrations/tomcat

我猜您可能已经看到了这一点,但是以防ehcache文档建议将lib放在tomcat中而不是在WEB-INF/lib中:http://ehcache.org/documentation/integrations/tomcat。

#5


1  

I recommend initializing thread locals, in a ServletRequestListener.

我建议在ServletRequestListener中初始化线程局部变量。

ServletRequestListener has 2 methods: one for initialization and one for destruction.

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

This way, you can cleanup your ThreadLocal. Example:

这样,您就可以清理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:

web . xml:

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

#1


36  

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将创建一个新的类装入器。旧的类装入器必须是垃圾收集,否则就会出现permgen内存泄漏。

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无法检查垃圾收集是否有效,但是它知道几个常见的故障点。如果webapp类加载器设置了一个ThreadLocal,该实例的类被webapp类加载器加载,那么servlet线程将引用该实例。这意味着类装入器不会被垃圾收集。

Tomcat does a number of such detections, see here for more information. Cleaning thread locals is difficult, you would have to call remove() on the ThreadLocal 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.

Tomcat做了许多这样的探测,在这里查看更多的信息。清理线程局部是困难的,您必须在每个被访问的线程中调用remove()。实际上,当您多次重新部署web应用程序时,这是非常重要的。在生产中,您可能不会重新部署,因此可以忽略这一点。

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.

要真正发现哪些实例定义了线程局部变量,必须使用分析器。例如JProfiler中的heap walker(声明:我的公司开发JProfiler)将帮助您找到这些线程本地。选择所报告的值类(com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty或com.sun.xml.bind.v2.ClassFactory),并显示已添加的传入引用。其中一个将是java.lang.ThreadLocal$ThreadLocalMap$Entry。为该传入引用类型选择引用对象,并切换到分配视图。您将看到实例的分配位置。有了这些信息,你就可以决定你是否能做些什么。

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

#2


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

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

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

and then adding this to our pom.xml

然后将它添加到我们的pom.xml中。

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

For more information, please refer to the project home page hosted on GitHub or Part 6 of his article

有关更多信息,请参考GitHub上的项目主页或他文章的第6部分。

#3


3  

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:

那些仍在为快速解决方案而犹豫不决的人,可以选择以下几点:

  • If running the standalone tomcat, kill javaw.exe or the process bearing it.
  • 如果运行独立的tomcat,则杀死javaw。exe或轴承的过程。
  • If running from eclipse, kill eclipse.exe and java.exe or enclosing process.
  • 如果在eclipse中运行,可以杀死eclipse。exe和java。exe或封闭的过程。
  • Still not resolved, Check for the task manager, it is likely that the process which is causing this will be shown with highest memory usage - Do your analysis and kill that.
  • 仍然没有解决,检查任务管理器,可能导致这一过程的过程将显示为最高的内存使用——做您的分析并杀死它。

You should be good to redeploy the stuff and proceed without memory issues.

您应该很好地重新部署这些内容,并且不需要内存问题。

#4


2  

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: http://ehcache.org/documentation/integrations/tomcat

我猜您可能已经看到了这一点,但是以防ehcache文档建议将lib放在tomcat中而不是在WEB-INF/lib中:http://ehcache.org/documentation/integrations/tomcat。

#5


1  

I recommend initializing thread locals, in a ServletRequestListener.

我建议在ServletRequestListener中初始化线程局部变量。

ServletRequestListener has 2 methods: one for initialization and one for destruction.

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

This way, you can cleanup your ThreadLocal. Example:

这样,您就可以清理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:

web . xml:

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