log4j2线程的Tomcat内存泄漏问题

Posted

技术标签:

【中文标题】log4j2线程的Tomcat内存泄漏问题【英文标题】:Tomcat memory leak issue of log4j2 thread 【发布时间】:2017-02-15 14:20:18 【问题描述】:

我使用 log4j2 进行日志记录,tomcat8 和 java8 版本。 我使用属性“monitorInterval”定期检查我的 log4j2.xml。 在关闭我的 tomcat 期间,我遇到了内存泄漏问题。如何解决此内存泄漏问题?

以下是 catalina 日志:

2016 年 10 月 6 日 15:13:55.927 警告 [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads Web 应用程序 [mywebapp] 似乎已启动 一个名为 [Log4j2-Log4j2Scheduled-1] 的线程,但未能阻止它。 这很可能造成内存泄漏。线程的堆栈跟踪: sun.misc.Unsafe.park(本机方法) java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215) java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078) java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093) java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809) java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067) java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) java.lang.Thread.run(Thread.java:745)

提前致谢。

更新: 我分析了我的日志,实际上一旦 Log4jServletContextListener 被破坏,记录器上下文就会再次初始化..

2016-10-22 13:49:36,347 localhost-startStop-2 调试 Log4jServletContextListener 确保 Log4j 正确关闭。 2016-10-22 13:49:36,382 localhost-startStop-2 调试开始 LoggerContext[名称=bb4719, org.apache.logging.log4j.core.LoggerContext@d77214]...

实际上在我的应用程序中,我在 web.xml 中使用了 spring ContextLoaderListner,因此它可能会在销毁 spring listner 的同时在内部使用日志记录。

谢谢

【问题讨论】:

你能粘贴 catalina 属性还是只粘贴 log4j 的行? 你可能想关注issues.apache.org/jira/browse/LOG4J2-1259 我已经查看了 log4j2-1259,我没有正确得出结论。 log4j-web.jar 丢失导致关闭挂钩无法正确执行。其他人也有同样的问题,但在他们的情况下,他们使用了一些旧的 catalina 属性,其中 log4j jar 被忽略了。 【参考方案1】:

它应该工作。

确保在构建中包含 log4j-web

例如作为maven依赖。

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-web</artifactId>
</dependency>

如果您使用的是 servlet 3.0 容器或更新的容器(如 Tomcat 8),则无需额外配置(只要您没有省略 Tomcat 来扫描某些 jar 中的 ServletContainerInitializer)。如需更多信息,请参阅Using Log4j 2 in Web Applications。


更新

我已经尝试使用您的设置(Tomcat 8.0.38,Log4j-2.6.2)并且它可以工作。要检查Log4jServletContextListenerLog4jServletFilter 是否已初始化,请在log4j2.xml 中将StatusLogger 级别设置为DEBUG

<Configuration monitorInterval="30" status="DEBUG">

之后,当应用部署时,您应该能够在根记录器附加程序中看到以下输出。

2016-10-14 20:21:36,762 RMI TCP Connection(2)-127.0.0.1 DEBUG Log4jServletContextListener ensuring that Log4j starts up properly.
2016-10-14 20:21:36,764 RMI TCP Connection(2)-127.0.0.1 DEBUG Log4jServletFilter initialized. 

如果您的应用被重新部署,您应该会在日志中看到以下几行。

2016-10-14 20:22:00,276 RMI TCP Connection(2)-127.0.0.1 DEBUG Log4jServletFilter destroyed.
2016-10-14 20:22:00,286 RMI TCP Connection(2)-127.0.0.1 DEBUG Log4jServletContextListener ensuring that Log4j shuts down properly.

如果您没有看到日志。如果您的 jarsToSkip 包含任何 log4j2 jar 或者您在 web.xml 中定义了值为 falseisLog4jAutoInitializationDisabled 参数,您应该检查您的 catalina.properties。

<context-param>
   <param-name>isLog4jAutoInitializationDisabled</param-name>
   <param-value>false</param-value>
</context-param> 

【讨论】:

我正在使用 servlet 3.0 容器。但仍然面临内存泄漏问题。我还更改了 catalina.properties,如 log4j2 文档中所述。 @Reetika,请准确告诉我们您使用的是哪个版本的 log4j2 和 Tomcat 8。 我使用的是log4j2-2.6.2版本和Tomcat8.0.38。我为 log4j2 日志实现添加了三个罐子 log4j-web-2.6.2.jar、log4j-core-2.6.2.jar、log4j-api.2.6.2.jar @Reetika,我检查了你的设置,它可以工作。有关详细信息,请参阅我的更新答案。 感谢@PaulWasilewski 抽出宝贵时间,之后我分析了我的日志【参考方案2】:

log4j-web 包含一个web-fragment.xml

<web-fragment xmlns="http://java.sun.com/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                                  http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd"
              version="3.0" metadata-complete="true">
    <!-- The Log4j web fragment must be loaded before all other fragments. The configuration below should make this
        happen automatically. If you experience problems, try specifying an <absolute-ordering> in your web.xml
        deployment descriptor. -->
    <name>log4j</name>
    <distributable />
    <ordering>
        <before>
            <others />
        </before>
    </ordering>
</web-fragment>

如果 webapp 包含多个片段,则首先加载此片段很重要。你在web.xml中配置这个:

<absolute-ordering>
    <name>log4j</name>
    <others/>
</absolute-ordering>

【讨论】:

以上是关于log4j2线程的Tomcat内存泄漏问题的主要内容,如果未能解决你的问题,请参考以下文章

Servlet“已启动一个线程但未能停止它”-Tomcat 中的内存泄漏

Tomcat Guice/JDBC 内存泄漏

Tomcat webapp 错误 - 应用程序启动线程 [AWT-Windows] 但未能阻止它 - 内存泄漏?

石英:内存泄漏?

Tomcat如何检测内存泄漏

怀疑 Jdbc 和 Tomcat 的内存泄漏