这很可能会在 Tomcat 中造成内存泄漏吗?

Posted

技术标签:

【中文标题】这很可能会在 Tomcat 中造成内存泄漏吗?【英文标题】:Is this very likely to create a memory leak in Tomcat? 【发布时间】:2011-07-14 14:56:28 【问题描述】:

我将 tomcat 配置为使用不同的外部开源。

但是,在tomcat运行几分钟后,我得到:

严重:Web 应用程序 [/MyProject] 创建了一个 ThreadLocal [java.lang.ThreadLocal] 类型的键(值 [java.lang.ThreadLocal@1b3f02f]) 和类型的值 [org.apache.axis.MessageContext](值 [org.apache.axis.MessageContext@5dbd4e]) 但在 Web 应用程序已停止。这很可能会创建一个 内存泄漏。

是什么原因造成的?

我必须看哪里?会不会是 Tomcat 上的数据池?

Tomcat 中的线程是什么意思?

已编辑

这是我的完整轨迹。该应用程序似乎在它仍在运行时重新加载其上下文 - 我不知道为什么!

Mar 13, 2011 10:56:12 PM org.apache.catalina.core.StandardContext reload
INFO: Reloading this Context has started
Mar 13, 2011 10:56:12 PM org.apache.catalina.core.StandardWrapper unload
INFO: Waiting for 1 instance(s) to be deallocated
Mar 13, 2011 10:56:13 PM org.apache.catalina.core.StandardWrapper unload
INFO: Waiting for 1 instance(s) to be deallocated
Mar 13, 2011 10:56:14 PM org.apache.catalina.core.StandardWrapper unload
INFO: Waiting for 1 instance(s) to be deallocated
Mar 13, 2011 10:56:14 PM org.apache.catalina.core.ApplicationContext log
INFO: Closing Spring root WebApplicationContext
Mar 13, 2011 10:56:15 PM org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc
SEVERE: The web application [/MyProject] registered the JBDC driver [com.mysql.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
Mar 13, 2011 10:56:15 PM org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc
SEVERE: The web application [/MyProject] registered the JBDC driver [oracle.jdbc.driver.OracleDriver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
Mar 13, 2011 10:56:15 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/MyProject] appears to have started a thread named [NiosocketAcceptor-1] but has failed to stop it. This is very likely to create a memory leak.
Mar 13, 2011 10:56:15 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/MyProject] appears to have started a thread named [NioProcessor-1] but has failed to stop it. This is very likely to create a memory leak.
Mar 13, 2011 10:56:15 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/MyProject] appears to have started a thread named [NioProcessor-4] but has failed to stop it. This is very likely to create a memory leak.
Mar 13, 2011 10:56:15 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/MyProject] appears to have started a thread named [bitronix-disk-force-batcher] but has failed to stop it. This is very likely to create a memory leak.
Mar 13, 2011 10:56:15 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/MyProject] appears to have started a thread named [bitronix-scheduler] but has failed to stop it. This is very likely to create a memory leak.
Mar 13, 2011 10:56:15 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/MyProject] is still processing a request that has yet to finish. This is very likely to create a memory leak. You can control the time allowed for requests to finish by using the unloadDelay attribute of the standard Context implementation.
Mar 13, 2011 10:56:15 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/MyProject] appears to have started a thread named [NioProcessor-7] but has failed to stop it. This is very likely to create a memory leak.
Mar 13, 2011 10:56:15 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/MyProject] appears to have started a thread named [NioProcessor-2] but has failed to stop it. This is very likely to create a memory leak.
Mar 13, 2011 10:56:15 PM org.apache.catalina.loader.WebappClassLoader clearThreadLocalMap
SEVERE: The web application [/MyProject] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@1b5a8e1]) and a value of type [org.mvel2.debug.DebuggerContext] (value [org.mvel2.debug.DebuggerContext@16259fd]) but failed to remove it when the web application was stopped. This is very likely to create a memory leak.
Mar 13, 2011 10:56:15 PM org.apache.catalina.loader.WebappClassLoader clearThreadLocalMap
SEVERE: The web application [/MyProject] created a ThreadLocal with key of type [org.apache.axis.utils.XMLUtils.ThreadLocalDocumentBuilder] (value [org.apache.axis.utils.XMLUtils$ThreadLocalDocumentBuilder@84b0b4]) and a value of type [com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl] (value [com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl@16d2cfa]) but failed to remove it when the web application was stopped. This is very likely to create a memory leak.
Mar 13, 2011 10:56:15 PM org.apache.catalina.loader.WebappClassLoader clearThreadLocalMap
SEVERE: The web application [/MyProject] created a ThreadLocal with key of type [null] (value [com.sun.faces.util.Util$1@16bbac9]) and a value of type [java.util.HashMap] (value [com.sun.faces.patternCache= = ]) but failed to remove it when the web application was stopped. This is very likely to create a memory leak.
Mar 13, 2011 10:56:15 PM org.apache.catalina.loader.WebappClassLoader clearThreadLocalMap
SEVERE: The web application [/MyProject] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@1b3f02f]) and a value of type [org.apache.axis.MessageContext] (value [org.apache.axis.MessageContext@5dbd4e]) but failed to remove it when the web application was stopped. This is very likely to create a memory leak.
Mar 13, 2011 10:56:15 PM org.apache.catalina.loader.WebappClassLoader clearThreadLocalMap
SEVERE: The web application [/MyProject] created a ThreadLocal with key of type [org.apache.axis.utils.XMLUtils.ThreadLocalDocumentBuilder] (value [org.apache.axis.utils.XMLUtils$ThreadLocalDocumentBuilder@84b0b4]) and a value of type [com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl] (value [com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl@378584]) but failed to remove it when the web application was stopped. This is very likely to create a memory leak.
Mar 13, 2011 10:56:15 PM org.apache.catalina.loader.WebappClassLoader clearThreadLocalMap
SEVERE: The web application [/MyProject] created a ThreadLocal with key of type [org.springframework.core.NamedThreadLocal] (value [Transactional resources]) and a value of type [java.util.HashMap] (value [org.hibernate.impl.SessionFactoryImpl@ccc27b=org.springframework.orm.hibernate3.SessionHolder@4f6ada]) but failed to remove it when the web application was stopped. This is very likely to create a memory leak.
Mar 13, 2011 10:56:15 PM org.apache.catalina.loader.WebappClassLoader clearThreadLocalMap
SEVERE: The web application [/MyProject] created a ThreadLocal with key of type [null] (value [com.sun.faces.application.ApplicationAssociate$1@1f01fcf]) and a value of type [com.sun.faces.application.ApplicationAssociate] (value [com.sun.faces.application.ApplicationAssociate@1b85528]) but failed to remove it when the web application was stopped. This is very likely to create a memory leak.
2011-03-13 22:57:27,734 ERROR (            ContextLoader.java:220)     - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in class path resource [applicationContext-hibernate.xml]: Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [applicationContext-hibernate.xml]: Invocation of init method failed; nested exception is java.lang.OutOfMemoryError: Java heap space
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:106)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1325)

【问题讨论】:

【参考方案1】:

消息实际上很清楚:某些东西创建了一个 ThreadLocal 类型为 org.apache.axis.MessageContext 的值 - 这是一个很好的提示。这很可能意味着 Apache Axis 框架忘记/未能自行清理。例如,在 Logback 中发生了相同的 problem。您不必费心,但向 Axis 团队报告错误可能是个好主意。

Tomcat 报告此错误是因为 ThreadLocals 是每个 HTTP 工作线程创建的。您的应用程序未部署,但 HTTP 线程仍然存在 - 这些 ThreadLocals 也是如此。这可能会导致内存泄漏(org.apache.axis.MessageContext 无法卸载)以及将来重用这些线程时的一些问题。

详情见:http://wiki.apache.org/tomcat/MemoryLeakProtection

【讨论】:

谢谢我用完整的跟踪编辑了我的问题-我仍然不明白为什么tomcat会开始重新加载中间的上下文,因此spring的应用程序上下文失败 您是否遇到意外的上下文重新加载?很少有人struggled 这样做。至于内存泄漏,它是由 Axis 产生的,而不是 You。但是您的上下文启动因堆内存不足而失败,这很奇怪 - 通常是 PermGen 很快就会用完。也许这个ThreadLocal 内存泄漏要严重得多?使用-XX:+HeapDumpOnOutOfMemoryError 诊断问题。 实际上为了管理上下文重新加载,我在 tomcat 中使用了 reloadable="false"。我知道 Java 代码或属性的任何更改都会迫使我重新启动服务器,但这是值得的。 大家好,“清理”到底是什么意思?我有一个 portlet,它创建了一个 ThreadLocal 变量。在每个请求结束时,我调用myLocalVar.remove();(并且该语句肯定会执行)但是当我更新portlet(取消部署+部署)时,liferay 多次记录提到的行:“创建了一个 ThreadLocal ... 删除它失败。 .. 内存泄漏。” 有一个 Spring 论坛指出此消息是 Tomcat(试图提供帮助)和 Web 应用程序帖子 forum.springsource.org/… 之间的交互中的错误功能,该帖子指出“不幸的是,没有公开用于故意删除依赖垃圾回收的 ThreadLocals 的 API。这是[影响]所有创建 ThreadLocal 的应用程序的东西。”【参考方案2】:

我在我的 CDI @ApplicationScoped bean 的 @PreDestroy 方法中添加了以下内容,当我关闭 TomEE 1.6.0(tomcat7.0.39,截至今天)时,它会清除线程局部变量。

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pf;

import java.lang.ref.WeakReference;
import java.lang.reflect.Array;
import java.lang.reflect.Field;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author Administrator
 * 
 * google-gson issue # 402: Memory Leak in web application; comment # 25
 * https://code.google.com/p/google-gson/issues/detail?id=402
 */
public class ThreadLocalImmolater 

    final Logger logger = LoggerFactory.getLogger(ThreadLocalImmolater.class);

    Boolean debug;

    public ThreadLocalImmolater() 
        debug = true;
    

    public Integer immolate() 
        int count = 0;
        try 
            final Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
            threadLocalsField.setAccessible(true);
            final Field inheritableThreadLocalsField = Thread.class.getDeclaredField("inheritableThreadLocals");
            inheritableThreadLocalsField.setAccessible(true);
            for (final Thread thread : Thread.getAllStackTraces().keySet()) 
                    count += clear(threadLocalsField.get(thread));
                    count += clear(inheritableThreadLocalsField.get(thread));
            
            logger.info("immolated " + count + " values in ThreadLocals");
         catch (Exception e) 
            throw new Error("ThreadLocalImmolater.immolate()", e);
        
        return count;
    

    private int clear(final Object threadLocalMap) throws Exception 
        if (threadLocalMap == null)
                return 0;
        int count = 0;
        final Field tableField = threadLocalMap.getClass().getDeclaredField("table");
        tableField.setAccessible(true);
        final Object table = tableField.get(threadLocalMap);
        for (int i = 0, length = Array.getLength(table); i < length; ++i) 
            final Object entry = Array.get(table, i);
            if (entry != null) 
                final Object threadLocal = ((WeakReference)entry).get();
                if (threadLocal != null) 
                    log(i, threadLocal);
                    Array.set(table, i, null);
                    ++count;
                
            
        
        return count;
    

    private void log(int i, final Object threadLocal) 
        if (!debug) 
            return;
        
        if (threadLocal.getClass() != null &&
            threadLocal.getClass().getEnclosingClass() != null &&
            threadLocal.getClass().getEnclosingClass().getName() != null) 

            logger.info("threadLocalMap(" + i + "): " +
                        threadLocal.getClass().getEnclosingClass().getName());
        
        else if (threadLocal.getClass() != null &&
                 threadLocal.getClass().getName() != null) 
            logger.info("threadLocalMap(" + i + "): " + threadLocal.getClass().getName());
        
        else 
            logger.info("threadLocalMap(" + i + "): cannot identify threadlocal class name");
        
    


【讨论】:

【参考方案3】:

关键的“事务资源”看起来就像您在没有正确事务的情况下与数据库交谈。确保正确配置事务管理,并且不存在不在 @Transactional 注释下运行的 DAO 调用路径。当您在控制器级别配置事务管理但在计时器中调用 DAO 或使用 @PostConstruct 注释时,很容易发生这种情况。我写在这里http://georgovassilis.blogspot.nl/2014/01/tomcat-spring-and-memory-leaks-when.html

编辑:看起来这(也是?)一个带有 spring-data-jpa 的错误,已在 v1.4.3 中修复。我在设置“事务资源”键的 LockModeRepositoryPostProcessor 的 spring-data-jpa 源中查找了它。在 1.4.3 中它还会再次清除密钥。

【讨论】:

【参考方案4】:

有时这与配置更改有关。当我们从 Tomncat 6.0.14 升级到 6.0.26 时,我们看到了类似的东西。这是解决方案 http://www.skill-guru.com/blog/2010/08/22/tomcat-6-0-26-shutdown-reports-a-web-application-created-a-threadlocal-threadlocal-has-been-forcibly-removed/

【讨论】:

【参考方案5】:

当我们使用任何第三方解决方案而不使用清理活动的处理程序时,就会出现此问题。 对我来说,这发生在 EhCache 上。我们在项目中使用 EhCache 进行缓存。 我们经常在日志中看到以下错误

 SEVERE: The web application [/products] appears to have started a thread named [products_default_cache_configuration] but has failed to stop it. This is very likely to create a memory leak.
Aug 07, 2017 11:08:36 AM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/products] appears to have started a thread named [Statistics Thread-products_default_cache_configuration-1] but has failed to stop it. This is very likely to create a memory leak.

而且我们在开发过程中经常注意到 tomcat 因 OutOfMemory 错误而失败,我们曾经进行后端更改并多次部署应用程序以反映我们的更改。

这是我们所做的修复

<listener>
  <listener-class>
     net.sf.ehcache.constructs.web.ShutdownListener
  </listener-class>
</listener>

所以我要说的是检查您正在使用的第三方库的文档。他们应该提供一些机制来在关闭期间清理线程。您需要在应用程序中使用它。 除非他们不提供,否则无需重新发明***。最坏的情况是提供您自己的实现。

EHCache 关闭参考 http://www.ehcache.org/documentation/2.8/operations/shutdown.html

【讨论】:

以上是关于这很可能会在 Tomcat 中造成内存泄漏吗?的主要内容,如果未能解决你的问题,请参考以下文章

服务器因 [Pool-Cleaner]:Tomcat 连接池而停止响应,但未能停止它。这很可能造成内存泄漏

Servlet“已启动一个线程但未能停止它”-Tomcat 中的内存泄漏

绑定会在 WPF 中造成内存泄漏吗?

Navigation Arch 组件会造成误报内存泄漏吗?

闭包会造成内存泄漏吗?

为啥lua语言中使用全局变量就会造成内存泄漏