Today I get PermGen OutOfMemory error.
Analysis showed that the closest GC Root for WebappClassLoader is the log stream:
this - value: org.apache.catalina.loader.WebappClassLoader #4 <- contextClassLoader (thread object) - class: java.lang.Thread, value: org.apache.catalina.loader.WebappClassLoader #4
which the:
java.lang.Thread#11 - logback-1
Dump the thread from the dump heap for this 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
I am using Tomcat 8 with the hot reloadable="true" function reloadable="true" and the external CLASSPATH via PreResources :
<Context docBase="/home/user/devel/app/src/main/webapp" reloadable="true"> <Resources> <PreResources className="org.apache.catalina.webresources.DirResourceSet" base="/home/user/devel/app/.config" internalPath="/" webAppMount="/WEB-INF/classes" /> </Resources> </Context>
and logback.xml with scan="true" :
<configuration debug="false" scan="true" scanPeriod="5 seconds"> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> ...
After saving the changes to the /home/user/devel/app/.config/logback.xml Tomcat 8 receipt notification (I'm not sure which API was used to monitor the changes in fs), and the application /home/user/devel/app/.config/logback.xml was started. This will happen before PermGen OutOfMemory .
How can I gracefully stop Logback in a container environment?
How to stop the stream "logback-1" ?
I found some related discussions, but can't figure out what to do with this information:
UPDATE I play with a bunch of heaps in visualvm . Under the link level, go from the bad logback-1 threads:
lvl1 = flatten(filter(referees(heap.findObject(0xf4c77610)), "!/WebappClassLoader/(classof(it).name)")) lvl2 = flatten(map(lvl1, "referees(it)")) lvl3 = flatten(map(lvl2, "referees(it)"))
he refers to
ch.qos.logback.core.util.ExecutorServiceUtil$1
By grepping in the log sources for ExecutorServiceUtil I found an entry in the change list :
All topics opened by ch.qos.logback.core.util.ExecutorServiceUtil # THREAD_FACTORY are now the daemons that fix the application, freeze when they shut down when LoggerContext # stop () is not called (LOGBACK-929). Note that daemon threads are abruptly interrupted by the JVM, which can cause unwanted results, such as corrupted files written by FileAppender. It is still highly recommended for applying gracefully closing applications to call LoggerContext # stop () (for example, at shutdown).
Is it right that in the stream of container daemons are dangerous and lead to memory leaks?