2015-12-28 7 views
5

Heute bekomme ich PermGen OutOfMemory Fehler.Anmutig stoppen Logback in Container-Umgebung

Analyse gezeigt, dass Nächster GC-Stamm für WebappClassLoader ist Logback thread:

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

das ist:

java.lang.Thread#11 - logback-1 

Thread-Dump aus Heapdump für diesen Thread:

"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) 

Ich verwende Tomcat 8 mit Hot Replay-Funktion reloadable="true" e und externalisiert CLASSPATH über PreResources:

<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> 

und logback.xml mit scan="true":

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

Nach der Änderung in /home/user/devel/app/.config/logback.xml Speichern Tomcat 8 erhalten eine Benachrichtigung (Ich bin nicht sicher, was API verwendet, um Änderungen an fs zu überwachen) und das erneute Bereitstellen der Anwendung wurde gestartet. Das passiert vor PermGen OutOfMemory.

Wie kann ich Logback in Container-Umgebung anmutig stoppen?

Wie zu stoppen "logback-1" thread?

fand ich ein paar ähnliche Diskussion aber nicht verstehen können, was mit dieser Info zu tun:

UPDATE Ich spiele mit Heap Dump in visualvm. Unter Bezugsebene Sprung von schlechten logback-1 thread:

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

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

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

verweisen sie auf

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

von greppen in Logback Quellen für ExecutorServiceUtil I found changelog entry:

Alle von ch geöffnet Fäden. qos.logback.core.util.ExecutorServiceUtil # THREAD_FACTORY sind jetzt Daemons, die eine Anwendung beim Herunterfahren behoben, wenn LoggerContext # stop() wird nicht aufgerufen (LOGBACK-929). Beachten Sie, dass Daemon-Threads abrupt von der JVM beendet werden, was zu unerwünschten Ergebnissen führen kann, z. B. zu beschädigten Dateien, die von FileAppender geschrieben wurden. Es wird weiterhin dringend empfohlen, dass die Anwendung LoggerContext # stop() (z. B. in einem Shutdown-Hook) auf aufruft, um Appender ordnungsgemäß herunterzufahren.

Ist das richtig, dass in Container-Umgebung Daemon Threads Gefahr sind und zu Speicherlecks führen?

Antwort

5

Ich bin nicht völlig zu verstehen, was ich tun soll. Ich entferne Derzeit jul-to-slf4j Brücke von Projekt pom.xml und diese Zeile:

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

von logback.xml. Auch bei dieser Linienanwendung haben Sie kein "logback-1" Gewinde.

As suggest official docs Ich registrieren:

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

in web.xml:

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

auf direkte Abhängigkeit zu entfernen:

import ch.qos.logback.classic.LoggerContext; 

Reflexion verwendet werden.

Nicht sicher, ob ich richtig mache. Ich werde sehen, ob PermGen OutOfMemory Fehler wegen Logback erhalten.

UPDATE Nachdem ich Referenz Abhängigkeit von ExecutorServiceUtil Klasse entdeckt habe ich Logback Quellen überprüft und festgestellt, dass diese Klasse über Themen mit Namen wie schlecht erstellen:

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

Diese Klasse verwendet nur in ch.qos.logback.core.ContextBase und Faden lehnte sich innen:

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

Beachten Sie, dass LoggerContext ist Unterklasse von ContextBase so oben s Lösung wirklich mein Problem beheben.

+0

Dank dies auch mein WebappClassLoader Leck behoben haben! – whitestryder

1

Ist das richtig, dass in Container-Umgebung Daemon Threads Gefahr sind und zu Speicherlecks führen?

Die Aussage über Daemon-Threads beziehen sich auf den Fall einer Stand-alone-Anwendung (wie im bug report), wo die JVM soll heruntergefahren werden, wenn die Anwendung beendet ist. Der Nicht-Daemon-Thread verhindert, dass die JVM heruntergefahren wird.

In einem JavaEE-Kontext, in dem die JVM des Anwendungsservers über mehrere Lebenszyklen mehrerer Anwendungen hinweg gleich bleibt, wirkt sich Daemon vs Nicht-Daemon nicht auf die Tatsache aus, dass live threads are GC roots.