Java ThreadLocal即使在清理后也会导致内存泄漏?

Java ThreadLocal即使在清理后也会导致内存泄漏?,java,tomcat,memory-leaks,jvm,thread-local,Java,Tomcat,Memory Leaks,Jvm,Thread Local,我有一个.war项目,它包含在接收HTTP调用前后设置和重置ThreadLocal的逻辑。从我运行的测试中,我非常确定这两个操作都正确执行,即ThreadLocal在设置后很快被清除。 为了测试我的项目,我有一个程序可以创建10个线程并从这些线程调用服务器。等待1秒后,此过程重复约500次。我的目标是监视正在消耗的堆存储,并确保没有内存泄漏 以下是我的重要观察结果: 当ThreadLocal未被使用时调用服务器:堆大小持续增加整个测试持续时间,并在测试完成后下降到测试前水平。 在使用Threa

我有一个.war项目,它包含在接收HTTP调用前后设置和重置
ThreadLocal
的逻辑。从我运行的测试中,我非常确定这两个操作都正确执行,即ThreadLocal在设置后很快被清除。 为了测试我的项目,我有一个程序可以创建10个线程并从这些线程调用服务器。等待1秒后,此过程重复约500次。我的目标是监视正在消耗的堆存储,并确保没有内存泄漏

以下是我的重要观察结果:

  • 当ThreadLocal未被使用时调用服务器:堆大小持续增加整个测试持续时间,并在测试完成后下降到测试前水平。
  • 在使用ThreadLocal时调用服务器(设置然后重置):对服务器的调用完成后,堆保留大部分已用空间。因此,内存正在泄漏。
  • 根据我对ThreadLocals使用的了解,如果不正确重置,它们可能会导致内存泄漏。但是,在我的情况下,我会采取适当的措施确保ThreadLocal被清除(在
    finally
    块中重置ThreadLocal。那么,是什么导致了内存泄漏,我如何解决它

    备注:以下是该项目的一些相关代码片段:

    //用于处理ThreadLocal实例的类
    公共类存储{
    私有静态ThreadLocal outboundRequestThread=new ThreadLocal();
    私有静态ThreadLocal inboundRequestThread=新ThreadLocal();
    公共静态字符串getOutboundRequestThread(){
    返回outboundRequestThread.get();
    }
    公共静态void setOutboundRequestThread(字符串值){
    outboundRequestThread.set(值);
    }
    公共静态无效clearOutboundThreadStorage(){
    outboundRequestThread.remove();
    }
    公共静态字符串getInboundRequestThread(){
    返回inboundRequestThread.get();
    }
    公共静态void setInboundRequestThread(字符串值){
    inboundRequestThread.set(值);
    }
    公共静态无效clearInboundThreadStorage(){
    inboundRequestThread.remove();
    }
    }
    
    //在通过rest模板进行HTTP调用之前设置ThreadLocal值
    公共TestData getData(…)抛出{
    ...
    setOutboundRequestThread(“测试值”);
    返回restemplate.exchange(…).getBody();
    }
    
    //重置捕获所有传入/传出HTTP调用的侦听器中的线程存储
    @凌驾
    公共ClientHttpResponse截获(HttpRequest请求,字节[]正文,ClientHttpPrequesteExecution执行)引发IOException{
    试一试{
    ClientHttpResponse response=execution.execute(请求,主体);
    logOutboundCall(请求、正文、响应);
    返回响应;
    }最后{
    EsStateStorage.clearOutboundThreadStorage();
    }
    }
    
    所以你有两个
    ThreadLocal
    实例和十个线程,你会想,它们是1GB内存消耗的原因吗?@Holger可能不会,但我担心的是,从图中可以看出,当我使用
    ThreadLocal
    时,没有垃圾清理。在我在问题中提到的两种情况中,唯一的我所做的nge是为了消除ThreadLocal的使用。其他一切都保持不变。这让我得出结论,ThreadLocal在某种程度上导致了堆空间被占用的保留。因此我的问题是,如果在堆大小达到1500MB时继续测试会发生什么?除此之外,当u“不要使用ThreadLocal”。通常,当您使用它们时,它们会达到一个目的,并且当该功能不可用时,受影响的代码必须急剧更改。从第一个图中的趋势来看,我假设堆大小将不断增加(超过1500MB)只要我不停地对服务器进行HTTP调用。另外,当我不使用ThreadLocal时,代码的更改是最小的。在我上面附加的代码片段中,为了禁用ThreadLocal的使用,我只需让
    EsStateStorage
    类的方法在被调用时不做任何操作。好的,这些方法
    getOutboundRequestThread()
    getInboundRequestThread()
    返回一些东西,如果此类不再存储值,它们必须返回null或一个虚构的值,因此换句话说,调用代码可能会在此基础上表现出完全不同的行为。关于行为,不要猜测,只需尝试。如果它继续增加,请使用强制堆大小限制运行并配置JVM要对内存不足错误进行堆转储,请分析堆转储以找出泄漏的位置。