Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java SLF4J MDC内存泄漏_Java_Tomcat_Memory Leaks_Slf4j_Mdc - Fatal编程技术网

Java SLF4J 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

我已经用谷歌搜索过了,看了很多建议,似乎没有任何帮助

我有一个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:

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>