2015-12-28 6 views
5

今日はPermGen OutOfMemoryエラーが発生します。コンテナ環境でLogbackを正常に停止する

this  - value: org.apache.catalina.loader.WebappClassLoader #4 
    <- contextClassLoader (thread object)  - class: java.lang.Thread, value: org.apache.catalina.loader.WebappClassLoader #4 

ある:このスレッドのためのヒープ・ダンプから

java.lang.Thread#11 - logback-1 

スレッドダンプ:

"logback-1" daemon prio=5 tid=34 WAITING 
at sun.misc.Unsafe.park(Native Method) 
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186) 
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:458) 
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:359) 
    Local Variable: java.util.concurrent.SynchronousQueue$TransferStack$SNode#1 
    Local Variable: java.util.concurrent.SynchronousQueue$TransferStack#6 
at java.util.concurrent.SynchronousQueue.take(SynchronousQueue.java:925) 
    Local Variable: java.util.concurrent.SynchronousQueue#6 
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1068) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130) 
    Local Variable: java.util.concurrent.ThreadPoolExecutor#34 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
    Local Variable: java.util.concurrent.ThreadPoolExecutor$Worker#11 
at java.lang.Thread.run(Thread.java:745) 

分析WebappClassLoaderためのGCルートはLogbackスレッドである最も近いことを示し

Tomcat 8をホットリデプロイ機能付きで使用していますE reloadable="true"とはPreResources経由CLASSPATHを外部化:scan="true"

<Context docBase="/home/user/devel/app/src/main/webapp" 
     reloadable="true"> 
    <Resources> 
     <!-- To override application.properties and logback.xml --> 
     <PreResources className="org.apache.catalina.webresources.DirResourceSet" 
         base="/home/user/devel/app/.config" 
         internalPath="/" 
         webAppMount="/WEB-INF/classes" /> 
    </Resources> 
</Context> 

logback.xml

<configuration debug="false" scan="true" scanPeriod="5 seconds"> 
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> 
    ... 

をTomcatの8 /home/user/devel/app/.config/logback.xmlに変更を保存した後は、(私がわからないどのようなFS上の変更を監視するために使用するAPI)の通知を受け取りますアプリケーションの再デプロイが開始されました。それはPermGen OutOfMemoryの前に起こります。

コンテナ環境でLogbackを正常に停止するにはどうすればよいですか?

"logback-1"スレッドを停止する方法はありますか?

私はいくつかの関連する説明を見つけましたが、その情報をどのように処理するかを理解することはできません。

UPDATE私はvisualvmのヒープダンプで遊んでいます。悪いlogback-1スレッドから参照ジャンプのレベルの下で:

lvl1 = flatten(filter(referees(heap.findObject(0xf4c77610)), "!/WebappClassLoader/(classof(it).name)")) 

lvl2 = flatten(map(lvl1, "referees(it)")) 

lvl3 = flatten(map(lvl2, "referees(it)")) 

それは私がfound changelog entryExecutorServiceUtilためLogback源にgrepをすることにより

ch.qos.logback.core.util.ExecutorServiceUtil$1 

を参照してください。

CHで開かれたすべてのスレッド。 qos.logback.core.util.ExecutorServiceUtil#THREAD_FACTORYは現在 デーモンであり、のシャットダウン時にアプリケーションがハングする問題を修正しましたLoggerContext#stop()が呼び出されていません(LOGBACK-929)。 デーモンスレッドがJVMによって突然終了することがあります。 は、FileAppender によって書き込まれた破損したファイルなどの望ましくない結果を引き起こします。アプリケーション は、LoggerContext#stop()(シャットダウンフックなど)を 正常終了アペンダに呼び出すことを強く推奨します。

コンテナ環境では、デーモンスレッドが危険でメモリリークにつながることは間違いありませんか?

答えて

5

私は何をすべきか十分に理解していません。 logback.xmlから

<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"/> 

:現在、私はjul-to-slf4jプロジェクトpom.xmlからブリッジと、この行を削除します。このラインアプリケーションでも、"logback-1"スレッドはありません。

As suggest official docs

Iレジスタ:web.xml

public class ShutdownCleanupListener implements ServletContextListener { 
    @Override 
    public void contextInitialized(ServletContextEvent sce) { } 

    @Override 
    public void contextDestroyed(ServletContextEvent sce) { 
     if (LoggerFactory.getILoggerFactory() instanceof LoggerContext) { 
      ((LoggerContext) LoggerFactory.getILoggerFactory()).stop(); 
     } 
    } 
} 

を:

<listener> 
    <listener-class>com.app.servlet.ShutdownCleanupListener</listener-class> 
</listener> 

に直接依存関係を削除するには、反射を使用することができる

import ch.qos.logback.classic.LoggerContext; 

私が正しいことをしているかどうかわかりません。 LogbackのためにPermGen OutOfMemoryエラーが表示されます。

UPDATE私はExecutorServiceUtilクラスから参照依存性を発見した後、私はLogbackソースをチェックし、このクラスは、上記の悪いような名前のスレッドを作成することがわかった:

thread.setName("logback-" + threadNumber.getAndIncrement()); 

のみch.qos.logback.core.ContextBaseスレッドで使用されるこのクラスは、アップ寄りかかっ内側:LoggerContextそうsを超えるContextBaseのサブクラスであること

public void stop() { 
    // We don't check "started" here, because the executor service uses 
    // lazy initialization, rather than being created in the start method 
    stopExecutorService(); 
    started = false; 
} 

注olutionは本当に私の問題を修正します。

+0

おかげで、これは同様に私のWebappClassLoaderリークを修正しました! – whitestryder

1

コンテナ環境でデーモンスレッドが危険であり、メモリリークを引き起こすことは間違いありませんか?

デーモンスレッドに関する声明は、JVMは、アプリケーションが終了したときにシャットダウンするようになっている(bug reportのように)、スタンドアローンアプリケーションの場合、を参照してください。非デーモンスレッドは、JVMのシャットダウンを防止します。

アプリケーションサーバーのJVMが、複数のアプリケーションの潜在的に複数のライフサイクルにわたって同じままであるJavaEEコンテキストでは、デーモンと非デーモンは、live threads are GC rootsという事実に影響しません。春ブーツlogbackプロジェクト例によると

1

、あなたはロギングシステムをクリーンアップするためにコンテキストを閉じる必要があります:https://github.com/spring-projects/spring-boot/commit/10402a651f1ee51704b58985c7ef33619df2c110

例:

public static void main(String[] args) throws Exception { 
     SpringApplication.run(SampleLogbackApplication.class, args).close(); 
    } 
+0

あなたの解決策は、Spring Boot対応アプリケーションのみに適用されることを理解しています... – gavenkoa

関連する問題