web-dev-qa-db-ja.com

Tomcat8のメモリリーク

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);
    }
}

このメモリリークエラーがすべて発生するのはなぜですか?また、シャットダウンを実行してもシャットダウンされません。手動でプロセスを強制終了する必要があります。

なにが問題ですか?

19
Dejell

心配することは何もありません。これは、アプリケーションが自身のThreadを開始したかThreadLocalを作成したことを検出したときにTomcatが出力する標準メッセージです。シャットダウン時にスレッドを終了し、threadlocalsが不要になったときに削除すると、問題はありません。

このメモリリークエラーがすべて発生するのはなぜですか?また、シャットダウンを実行してもシャットダウンされません。手動でプロセスを強制終了する必要があります。

アプリケーションがScheduledExecutor(ただし、これは他のThread/TheadPoolで開始され、contextDestroyedでシャットダウンしなかったときに、この動作を確認しました。 。そのため、アプリケーション/サーバーの停止時にスレッドをシャットダウンしているかどうかを確認してください。

今、あなたの具体的な問題についてサーバーが停止しない理由:JDBCドライバーはシングルトンとしてJVMに登録され、すべてのwebappsと共有されます。詳細情報 こちら 問題に対する最善の解決策は、MySQLドライバーをTomcatの/libフォルダー。それができない場合は、 this を試すことができますが、実際のソリューションというよりはハックのようです。

19
Svetlin Zarev

あなたの問題は this に似ていると思います。アプリを再デプロイすると、Apacheはそれをsystem.gc();が機能しない自分自身に増分的にデプロイし、開発段階での再デプロイを数回行った後、永続的に生成されたスペースがいっぱいになり、メモリリークエラーが発生します。

数回再デプロイした後、サーバーを再起動し続けるようにしてください。再起動でPermGenスペースをクリアできます。

または

サーバーのPermGenスペースを変更することでも解決できます。 こちら にアクセスしてください。

これがお役に立てば幸いです。

1
Ravi Chhatrala