Tomcat8内存泄漏问题

25

当我尝试在Java 8上停止tomcat8时,会出现一些内存泄漏错误:

org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ROOT] appears to have started a thread named [Abandoned connection cleanup thread] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
 java.lang.Object.wait(Native Method)
 java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:142)
 com.mysql.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:40)
23-Jan-2015 08:18:10.202 WARNING [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ROOT] appears to have started a thread named [pool-5-thread-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread


23-Jan-2015 08:18:10.205 SEVERE [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [ROOT] created a ThreadLocal with key of type [com.util.ThreadLocalProperties$1] (value [com.util.ThreadLocalProperties$1@2fafda6e]) and a value of type [java.util.Properties] (value [{}]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.

ThreadLocalProperties类是:

public class ThreadLocalProperties extends Properties {

    private static final long serialVersionUID = -4260632266508618756L;
    private final ThreadLocal<Properties> localProperties = new ThreadLocal<Properties>() {
        @Override
        protected Properties initialValue() {
            return new Properties();
        }
    };

    public ThreadLocalProperties(Properties properties) {
        super(properties);
    }

    @Override
    public String getProperty(String key) {
        String localValue = localProperties.get().getProperty(key);
        return localValue == null ? super.getProperty(key) : localValue;
    }

    @Override
    public Object setProperty(String key, String value) {
        return localProperties.get().setProperty(key, value);
    }

    public ThreadLocal<Properties> getThreadLocal() {
        return localProperties;
    }
}

我像这样开始和停止它:

@WebListener()
public class GeneralListener implements ServletContextListener {

    ThreadLocalProperties threadLocalProperties = new ThreadLocalProperties(System.getProperties());

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        threadLocalProperties.getThreadLocal().remove();
    }

    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        System.setProperties(threadLocalProperties);
    }
}

为什么我会收到所有这些内存泄漏错误?而且,当我运行关闭命令时,它不能正常关闭,我必须手动杀死进程。

出了什么问题?


http://docs.oracle.com/cd/E17952_01/connector-j-relnotes-en/news-5-1-23.html - David
2个回答

26

不用担心,这是Tomcat检测到应用程序已经启动了自己的Thread或创建了ThreadLocal时输出的标准消息。如果您在关闭时终止线程并在不再需要时删除threadlocals,那么就不会有问题。

为什么我会收到所有这些内存泄漏错误?而且当我运行关闭时,它并没有关闭,我必须手动杀死进程。

当应用程序启动了ScheduledExecutor(但任何其他Thread/TheadPool也会发生这种情况)并且没有在contextDestroyed上关闭它时,我见过这种行为。因此,请检查您是否在应用程序/服务器停止时关闭了线程。

现在针对您的具体问题,为什么服务器无法停止: JDBC驱动程序在JVM中注册为单例,并与所有Web应用程序共享。更多信息在这里。解决您的问题的最佳方法是将MySQL驱动程序从Web应用程序的WEB-INF/lib移动到Tomcat的/lib文件夹中。如果您无法这样做,可以尝试这个,但这更像是一个hack而不是真正的解决方案。


谢谢。是的,它真的有帮助!有趣的是,如果我部署我的名为“Algo”的应用程序,并在 server.xml 中使用以下代码:<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Context docBase="Algo" path=""> <WatchedResource>WEB-INF/web.xml</WatchedResource> </Context> 它将同时将“Algo” war 部署到“Algo”文件夹和“ROOT”文件夹中! - Dejell
3
将mysql驱动程序移动到Tomcat的/lib文件夹中对我没有起作用。 - Neets
你是否从/WEB-INF/lib中删除了驱动程序?如果你的应用程序启动线程但没有停止它们,也会收到这个消息。 - Svetlin Zarev

1
我认为你的问题类似于this。当你重新部署应用程序时,Apache会在自身上递增地部署它,其中system.gc();不起作用,在开发阶段进行几次重新部署后,永久生成的空间变满,导致内存泄漏错误。
请在几次重新部署后保持服务器重启,这样PermGen空间就可以通过重启清除。
或者
您还可以通过更改服务器中的PermGen空间来解决此问题。请访问here
希望这可以帮助到你。

我不重新部署服务器。我会通过./shutdown和./startup对其进行重启。我相信这样可以清除perm大小,对吗? - Dejell
另外,当我尝试向Tomcat8添加perm大小定义时,我收到一个警告,说它被忽略了。 - Dejell
你是否也在运行Java 8?我不是100%确定,但我认为从该版本开始,permgen空间已经变得无关紧要。我看不出Tomcat记录的这些信息警告消息与permgen空间有任何关系,如果您正在硬重启服务器,则它们也不需要担心。 - Gimby
我并不是在说重新部署你的服务器,而是指重新部署你正在尝试在Apache Tomcat服务器上运行的Web应用程序。每次保存和构建应用程序时,它都会创建一个.war文件,对吧?然后这个文件将被增量重新部署。(这将在几次构建后引发内存泄漏错误。) - Ravi Chhatrala
1
@Dejel 尝试手动更改PermGen空间:在Windows上设置环境变量,手动创建一个setenv.bat文件,并将其放置在${tomcat-folder}\bin文件夹中。 ${tomcat-folder}\bin\setenv.bat 设置 JAVA_OPTS=-Dfile.encoding=UTF-8 -Xms128m -Xmx1024m -XX:PermSize=64m -XX:MaxPermSize=256m 或更高。这样就不会再出现关于此问题的任何警告,并且也不会被忽略。 - Ravi Chhatrala
是的,我正在运行Java 8,并且它已经变得不相关了。 - Dejell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接