gav*_*koa 5 tomcat out-of-memory logback permgen redeploy
今天我收到PermGen OutOfMemory错误.
显示,分析最近的GC根为WebappClassLoader是的logback螺纹:
this - value: org.apache.catalina.loader.WebappClassLoader #4
<- contextClassLoader (thread object) - class: java.lang.Thread, value: org.apache.catalina.loader.WebappClassLoader #4
Run Code Online (Sandbox Code Playgroud)
这是:
java.lang.Thread#11 - logback-1
Run Code Online (Sandbox Code Playgroud)
来自此线程的堆转储的线程转储:
"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)
Run Code Online (Sandbox Code Playgroud)
我使用具有热重新部署功能的Tomcat 8 reloadable="true"并CLASSPATH通过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>
Run Code Online (Sandbox Code Playgroud)
并logback.xml与scan="true":
<configuration debug="false" scan="true" scanPeriod="5 seconds">
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
...
Run Code Online (Sandbox Code Playgroud)
在/home/user/devel/app/.config/logback.xmlTomcat 8中保存修改后,接收通知(我不确定用于监视fs更改的API)并启动了应用程序重新部署.这就是以前发生的事情PermGen OutOfMemory.
如何在容器环境中优雅地停止Logback?
如何阻止"logback-1"线程?
我找到了一些相关的讨论,但无法理解如何处理该信息:
更新我玩堆转储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)"))
Run Code Online (Sandbox Code Playgroud)
它指的是
ch.qos.logback.core.util.ExecutorServiceUtil$1
Run Code Online (Sandbox Code Playgroud)
通过在Logback源中为ExecutorServiceUtil我找到changelog条目:
ch.qos.logback.core.util.ExecutorServiceUtil #THREAD_FACTORY打开的所有线程现在都是守护进程,当没有调用LoggerContext#stop()时,它会修复关闭时的应用程序挂起(LOGBACK-929).请注意,守护程序线程突然被JVM终止,这可能会导致不良结果,例如FileAppender写入的文件损坏.仍然强烈建议应用程序调用LoggerContext #stop()(例如,在关闭钩子中)以正常关闭appender.
是否正确,在容器环境守护程序线程是危险的,并导致内存泄漏?
我不完全明白我该怎么做.目前我jul-to-slf4j从项目pom.xml和此行删除桥:
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"/>
Run Code Online (Sandbox Code Playgroud)
来自logback.xml.即使这个行应用程序没有"logback-1"线程.
作为官方文档的建议,我注册:
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
在web.xml:
<listener>
<listener-class>com.app.servlet.ShutdownCleanupListener</listener-class>
</listener>
Run Code Online (Sandbox Code Playgroud)
删除直接依赖:
import ch.qos.logback.classic.LoggerContext;
Run Code Online (Sandbox Code Playgroud)
可以使用反射.
不确定我做得对.我会看到PermGen OutOfMemory因为Logback而得到错误.
更新在我发现ExecutorServiceUtil类I的引用依赖项后,检查了Logback源并发现此类创建的线程名称与上面的错误相同:
thread.setName("logback-" + threadNumber.getAndIncrement());
Run Code Online (Sandbox Code Playgroud)
这个类只用于ch.qos.logback.core.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;
}
Run Code Online (Sandbox Code Playgroud)
请注意,LoggerContext是的子类,ContextBase所以上述方案真正解决我的问题.
| 归档时间: |
|
| 查看次数: |
1923 次 |
| 最近记录: |