Tomcat的log4j2线程内存泄漏问题

7
我正在使用log4j2记录日志,tomcat8和java8版本。我使用"monitorInterval"属性定期检查log4j2.xml。在关闭我的tomcat时,我遇到了内存泄漏的问题。如何解决这个内存泄漏问题?
以下是catalina日志: 06-Oct-2016 15:13:55.927 WARNING [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 DEBUG Log4jServletContextListener确保Log4j正常关闭。 2016-10-22 13:49:36,382 localhost-startStop-2 DEBUG启动LoggerContext [name=bb4719, org.apache.logging.log4j.core.LoggerContext@d77214]......
实际上,在我的应用中,我在web.xml中使用spring ContextLoaderListner,所以在销毁spring listner时可能会在内部使用日志记录。
谢谢。

你能粘贴catalina属性或者只是包含log4j的行吗? - bhantol
你可能想要关注 https://issues.apache.org/jira/browse/LOG4J2-1259 - bhantol
我研究了log4j2-1259,但是没有完全理解它的结论。 - Reetika
log4j-web.jar文件丢失,导致关闭挂钩无法正常执行。其他人也遇到了同样的问题,但在他们的情况下,他们使用了一些旧的catalina属性,其中忽略了log4j jars。 - bhantol
2个回答

6

这应该可以工作。

确保在您的构建中包含log4j-web

例如,作为Maven依赖项。

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

如果您正在使用Servlet 3.0容器或更高版本(例如Tomcat 8),则不需要进行其他配置(只要您没有遗漏在某些jar中扫描ServletContainerInitializer的Tomcat)。有关更多信息,请参见在Web应用程序中使用Log4j 2

更新

我已经尝试过您的设置(Tomcat 8.0.38,Log4j-2.6.2),它可以工作。如果要检查是否初始化了 Log4jServletContextListener Log4jServletFilter ,请将 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.

如果您没有看到日志,则应检查您的catalina.properties文件,是否包含任何log4j2的jar包或者是否在您的web.xml中定义了一个isLog4jAutoInitializationDisabled参数,并将其值设置为false。

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

我正在使用servlet 3.0容器,但仍然遇到内存泄漏问题。我也按照log4j2文档中的说明更改了catalina.properties文件。 - Reetika
@Reetika,请告诉我们您正在使用的log4j2和Tomcat 8的确切版本。 - Paul Wasilewski
我正在使用log4j2-2.6.2版本和Tomcat8.0.38。我添加了三个jar包log4j-web-2.6.2.jar,log4j-core-2.6.2.jar,log4j-api.2.6.2.jar来实现log4j2日志记录功能。 - Reetika
@Reetika,我已经检查了你的设置并且它是有效的。请查看我的更新答案以获取详细信息。 - Paul Wasilewski
感谢@PaulWasilewski抽出时间来,我分析了我的日志。 - Reetika
关注 https://logging.apache.org/log4j/2.x/manual/webapp.html 并添加所需的过滤器和监听器(因为我的应用程序是Servlet 2.4),似乎解决了我的问题。 - Osmar

0

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>

如果 Web 应用程序包含多个片段,则此片段被首先加载非常重要。您可以在 web.xml 中进行配置:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接