我目前使用的堆栈是:
- log4j2 rc1
- 弹簧3.2型芯和腹板
- tomcat 7.0.47
- java 1.6.0_45
- Windows 7
我没有能力更改tomcat版本或java版本,我更希望不更改log4j版本和spring版本。
本质上,当我取消部署我的网络应用程序时,我会收到一个严重的警告,上面写着:
SEVERE: The web application [/MyApp] appears to have started a thread named
[AsyncAppender-AsyncFile] but has failed to stop it. This is very likely to
create a memory leak
我可以确认它确实造成了内存泄漏,这就是我正在努力解决的问题。
到目前为止,我已经尝试创建一个自定义Servlet上下文侦听器,其中包含以下代码:
@Override
public void contextDestroyed(ServletContextEvent event) {
System.out.println("Shutting down logger");
try {
((Log4jWebSupport) event.getServletContext().getAttribute(
Log4jWebSupport.SUPPORT_ATTRIBUTE)).clearLoggerContext();
((LifeCycle) LogManager.getContext()).stop();
} catch (Exception e) {
}
}
这两行似乎都不能解决问题,但我可以确认,由于我的sysout语句出现在tomcat控制台中,所以这段代码正在执行。
我正在通过一个拦截器使用log4j2,我正在使用Spring 设置该拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<ref bean="LoggingInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<bean id="LoggingInterceptor" class="MyLoggerClass">
拦截器工作正常,日志显示在我期望的地方。我对记录器的实现是:
private static Logger log = LogManager.getLogger("MetricLogger");
public void log(LogPayload payload) {
if(payload != null){
log.info(payload.get());
}
}
其中LogPayload.get()
返回一个字符串。
当我在多个web应用程序中使用日志记录功能时,我创建了一个单独的jar文件,其中包含这个和记录测量的类。我已经使用maven将其包含在内,并将其编译到部署到tomcat的最终war文件中。此war文件按应用程序包含,不包含在全局tomcat/lib文件夹中。
有人知道我为什么会出现内存泄漏问题,以及解决这个问题的可能解决方案吗?
非常感谢您的帮助,如果您需要更多信息,请告诉我。
到目前为止,我找到的解决方案是,我需要在web.xml中包含以下代码段。
<listener>
<listener-class>org.apache.logging.log4j.core.web.Log4jServletContextListener</listener-class>
</listener>
<filter>
<filter-name>log4jServletFilter</filter-name>
<filter-class>org.apache.logging.log4j.core.web.Log4jServletFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>log4jServletFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
这是servlet规范2.5特有的。这似乎解决了内存泄漏问题。
如果你最近遇到这个问题,你应该注意以下几点:
如果您使用的是servlet 3.0+和tomcat>7.0.43或Tomcat8不需要任何配置,您只需要提供正确的maven依赖项,就可以让log4j2知道在如下Web容器中运行(此外,我们使用slf4j):
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-web</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.11.0</version>
</dependency>
由于在我们的案例中log4j web工件丢失,我们面临着相同的警告,上面写着";。。。已启动名为[AncAppender AsyncFile]的线程,但未能停止它"
在提供了上述依赖关系之后,警告就消失了。
您可以在这里阅读更多关于需求的信息
添加以下代码段使我摆脱了由于异步Appender线程即使在应用程序关闭后也没有关闭而导致的内存泄漏。谢谢@kipper_t。
<listener>
<listener-class>org.apache.logging.log4j.core.web.Log4jServletContextListener</listener-class>
</listener>
<filter>
<filter-name>log4jServletFilter</filter-name>
<filter-class>org.apache.logging.log4j.core.web.Log4jServletFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>log4jServletFilter</filter-name>
<url-pattern>/*</url-pattern>