Java SLF4J MDC内存泄漏
我已经用谷歌搜索过了,看了很多建议,似乎没有任何帮助 我有一个JAX-RS应用程序,它使用MDC,当一个端点被命中时,设置一个transactionId,以使调试更容易。但是,当我停止或重新启动Tomcat时,日志中会充满如下条目: 2014年9月27日09:42:14.858严重[localhost-startStop-2]org.apache.catalina.loader.WebappClassLoader.checkThreadLocalMapForLeaks web应用程序[/core-1.0.0-RC2]创建了一个ThreadLocal,其密钥类型为[org.apache.log4j.helpers.ThreadLocalMap](值为[org.apache.log4j.helpers)。ThreadLocalMap@464437fc])和类型的值[java.util.Hashtable](值[{siteCode=000tst,transactionId=dc8f3a1b-1d7a-4f91-abf6-58d015632d03}]),但在web应用程序停止时无法将其删除。将随着时间的推移更新线程,以尝试避免可能的内存泄漏 我有一个RequestFilter,其中调用了MDC:Java SLF4J MDC内存泄漏,java,tomcat,memory-leaks,slf4j,mdc,Java,Tomcat,Memory Leaks,Slf4j,Mdc,我已经用谷歌搜索过了,看了很多建议,似乎没有任何帮助 我有一个JAX-RS应用程序,它使用MDC,当一个端点被命中时,设置一个transactionId,以使调试更容易。但是,当我停止或重新启动Tomcat时,日志中会充满如下条目: 2014年9月27日09:42:14.858严重[localhost-startStop-2]org.apache.catalina.loader.WebappClassLoader.checkThreadLocalMapForLeaks web应用程序[/core
import org.slf4j.MDC;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import java.io.IOException;
import java.util.UUID;
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
String siteCodeHeader = containerRequestContext.getHeaderString("Site-Code");
if (siteCodeHeader != null) {
MDC.put("siteCode", siteCodeHeader);
} else {
MDC.put("siteCode", "NULL");
}
MDC.put("transactionId", UUID.randomUUID().toString());
}
以下是我的sl4fj依赖项:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.7</version>
</dependency>
org.slf4j
slf4j api
1.7.7
org.slf4j
slf4j-log4j12
1.7.7
如果我有一个带有MDC.clear()的ResponseFilter,它会从MDC中删除值,但似乎不会清除线程:
2014年9月27日09:12:58.216严重[localhost-startStop-2]org.apache.catalina.loader.WebappClassLoader.checkThreadLocalMapForLeaks web应用程序[/core-1.0.0-RC2]创建了一个ThreadLocal,其密钥类型为[org.apache.log4j.helpers.ThreadLocalMap](值为[org.apache.log4j.helpers)。ThreadLocalMap@391216c7])和类型的值[java.util.Hashtable](值[{}]),但在web应用程序停止时无法将其删除。将随着时间的推移更新线程,以尝试避免可能的内存泄漏
显然,它在log4j 1.2.17中已修复,但更改似乎没有渗透到slf4j。这显然不是slf4j问题,只是log4j问题。使用
运行时范围将固定的log4j版本作为直接依赖项添加到POM中,您的问题应该会消失。使用ThreadLocal
。如果在筛选器中添加值,则必须在服务调用后将其删除
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try
{
//add your mdcs
// proceed along the chain
chain.doFilter(request, response);
}
finally
{
//remove your mdcs
}
}
使用前两个答案的组合,我能够解决这个问题
我使用了MDC的log4j实现,而不是SLF4J,并添加了一个ResponseFilter来进行清除。这可能会影响它,也可能不会影响它,但我还使用了提供者注释,而不是在web.xml中规定类
RequestFilter(大致相同):
响应过滤器:
package com.example.jaxrs;
import org.apache.log4j.MDC;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
@Provider
public class TransactionIdentifierResponseFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) throws IOException {
MDC.clear();
}
}
web.xml
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.example.jaxrs</param-value>
</init-param>
jersey.config.server.provider.packages
com.example.jaxrs
不起作用。我使用的是MDC的SLF4j版本,而不是Log4J,Log4J的最新版本是另一个依赖项的依赖项,因此已经存在。然后,在处理请求后,您错过了清理MDC。我在之后清理了MDC,并返回虽然值已清除,但threadlocal仍然是remaining。尝试使用logback,查看是否仍然存在内存泄漏。添加log4j依赖项版本1.2.17解决了此问题。我创建了一个扩展ServletContainer的类,覆盖了doFilter()方法并将Spring中的servlet类设置为我的自定义类,但是doFilter似乎没有被命中。我是否需要以某种方式显式调用doFilter?在servlet 3.0规范之前,人们会向web.xml文件添加一个筛选器配置。请看一看,这是一种错误的方法。您现在已经将代码绑定到Log4J。您应该清除了t首先,他使用了MDC。它不起作用。SLF4J MDC是在1.2.17补丁发布之前在旧版本的log4j上构建的。通过查看实际的源代码发现了这一点。我用于SLF4J的底层日志框架是log4j,因此不需要任何新的依赖项等,也不需要进行完整的日志检查。这就是我建议更新的原因log4j。
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.example.jaxrs</param-value>
</init-param>