`
yangyi
  • 浏览: 115724 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

关于ThreadLocal的内存泄露

阅读更多
ThreadLocal是一种confinement,confinement和local及immutable都是线程安全的(如果JVM可信的话)。因为对每个线程和value之间存在hash表,而线程数量未知,从表象来看ThreadLocal会存在内存泄露,读了代码,发现实际上也可能会内存泄露。

事实上每个Thread实例都具备一个ThreadLocal的map,以ThreadLocal Instance为key,以绑定的Object为Value。而这个map不是普通的map,它是在ThreadLocal中定义的,它和普通map的最大区别就是它的Entry是针对ThreadLocal弱引用的,即当外部ThreadLocal引用为空时,map就可以把ThreadLocal交给GC回收,从而得到一个null的key。

这个threadlocal内部的map在Thread实例内部维护了ThreadLocal Instance和bind value之间的关系,这个map有threshold,当超过threshold时,map会首先检查内部的ThreadLocal(前文说过,map是弱引用可以释放)是否为null,如果存在null,那么释放引用给gc,这样保留了位置给新的线程。如果不存在slate threadlocal,那么double threshold。除此之外,还有两个机会释放掉已经废弃的threadlocal占用的内存,一是当hash算法得到的table index刚好是一个null key的threadlocal时,直接用新的threadlocal替换掉已经废弃的。另外每次在map中新建一个entry时(即没有和用过的或未清理的entry命中时),会调用cleanSomeSlots来遍历清理空间。此外,当Thread本身销毁时,这个map也一定被销毁了(map在Thread之内),这样内部所有绑定到该线程的ThreadLocal的Object Value因为没有引用继续保持,所以被销毁。

从上可以看出Java已经充分考虑了时间和空间的权衡,但是因为置为null的threadlocal对应的Object Value无法及时回收。map只有到达threshold时或添加entry时才做检查,不似gc是定时检查,不过我们可以手工轮询检查,显式调用map的remove方法,及时的清理废弃的threadlocal内存。需要说明的是,只要不往不用的threadlocal中放入大量数据,问题不大,毕竟还有回收的机制。

综上,废弃threadlocal占用的内存会在3中情况下清理:
1 thread结束,那么与之相关的threadlocal value会被清理
2 GC后,thread.threadlocals(map) threshold超过最大值时,会清理
3 GC后,thread.threadlocals(map) 添加新的Entry时,hash算法没有命中既有Entry时,会清理
那么何时会“内存泄露”?当Thread长时间不结束,存在大量废弃的ThreadLocal,而又不再添加新的ThreadLocal(或新添加的ThreadLocal恰好和一个废弃ThreadLocal在map中命中)时。
分享到:
评论
9 楼 lovbreath 2010-07-05  
yumcn.com 写道
没看过源代码,理论上是这样吧。
Thread有长时间不结束的情况吗?除非定时器,但是一个应用的定时器最多也是有限的几
个,如果一个应用有长时间不结束的Thread,就要检查代码写的是否有问题了。
另外,一个应用处理高并发的时候都会建立线程池,控制线程的最大值。
我觉得还是可以使用Threalocal来做应用开发的。


用ThreadLocal来做开发当然没问题。说白了,SUN引入ThreadLocal无非就是在解决变量共享冲突问题上用空间来换时间,所以处理不好有泄漏应该算是合理的。
我在前一阵刚读过ThreadLocal的源代码,对比LZ的分析很惭愧啊,看来应该多学习LZ的精神啊。

引用

那么何时会“内存泄露”?当Thread长时间不结束,存在大量废弃的ThreadLocal,而又不再添加新的ThreadLocal(或新添加的ThreadLocal恰好和一个废弃ThreadLocal在map中命中)时。


如果当ThreadLocal遇到线程池,那么发生泄漏的几率会大一些呢?
8 楼 poppk 2010-07-05  
要善于和je的恶势力作斗争,精华了。
7 楼 C_J 2010-07-04  
- -! 你的意思是说:ThradLocal的内部类ThreadLocalMap这个map下的Entry在某些情况下存在内存泄漏吗?

  但这个Entry是弱引用,应该是被GC启动时无条件回收吧?而弱引用并不被JVM"标记",每次GC都回收的呀,还是我理解有误?
6 楼 rain2005 2010-07-04  
static  ThreadLocal
5 楼 gogole_09 2010-07-04  
赞楼主的精神先,但个人有个小建议, 在解释文字中,可以适量加一些代码,或者使文章更有可读性。
4 楼 czpsailer 2010-07-04  
为啥这么多人投隐藏,如果LZ那里说的不对可以指出,让大家学习下呀。我觉得至少LZ精神可嘉的。
3 楼 yangyi 2010-07-03  
yumcn.com 写道
没看过源代码,理论上是这样吧。
Thread有长时间不结束的情况吗?除非定时器,但是一个应用的定时器最多也是有限的几
个,如果一个应用有长时间不结束的Thread,就要检查代码写的是否有问题了。
另外,一个应用处理高并发的时候都会建立线程池,控制线程的最大值。
我觉得还是可以使用Threalocal来做应用开发的。

恩,因为一直有人说ThreadLocal存在内存泄露问题,我才探究了一下,事实上问题不大。所谓内存泄露更多是出于一种性能的考量
2 楼 yumcn.com 2010-07-03  
没看过源代码,理论上是这样吧。
Thread有长时间不结束的情况吗?除非定时器,但是一个应用的定时器最多也是有限的几
个,如果一个应用有长时间不结束的Thread,就要检查代码写的是否有问题了。
另外,一个应用处理高并发的时候都会建立线程池,控制线程的最大值。
我觉得还是可以使用Threalocal来做应用开发的。
1 楼 yangyi 2010-07-02  
本文基于对源代码的理解,如有错误请指正

相关推荐

    ThreadLocal 内存泄露的实例分析1

    但这里,`ThreadLocal` 的设计使得其内部的引用(即使是最弱的引用)在类加载器试图卸载时依然存在,这就形成了一个内存泄漏点。 解决这个问题的关键在于,我们需要确保在不再需要 `ThreadLocal` 变量时,及时清除...

    ThreadLocal内存泄露分析

    【标题】:“ThreadLocal内存泄露分析” 在Java编程中,ThreadLocal是一个强大的工具类,它为每个线程提供了一个独立的变量副本,使得每个线程都可以独立地改变自己的副本,而不会影响其他线程所对应的副本。然而,...

    ThreadLocal中内存泄漏和数据丢失问题的问题浅析及解决方案.docx

    ThreadLocal 中内存泄漏和数据丢失问题的问题浅析及解决方案 ThreadLocal 是 Java 中的一种线程本地存储机制,它可以解决线程之间的数据传递问题。然而,在使用 ThreadLocal 时,可能会出现内存泄漏和数据丢失问题...

    ThreadLocal内存泄漏思维导图完整版

    内存泄漏就是JVM垃圾回收器对某个对象占据的内存在较长时间内一直没法回收,没法回收的原因并不是因为垃圾回收器有bug,而是由于对象没法判定为垃圾(但实际上该对象已经是不会被使用了)。这里说的“较长时间”是一...

    04、导致JVM内存泄露的ThreadLocal详解-ev

    04、导致JVM内存泄露的ThreadLocal详解_ev04、导致JVM内存泄露的ThreadLocal详解_ev04、导致JVM内存泄露的ThreadLocal详解_ev04、导致JVM内存泄露的ThreadLocal详解_ev04、导致JVM内存泄露的ThreadLocal详解_ev04、...

    ThreadLocal原理及内存泄漏原因

    让我们深入理解ThreadLocal的工作原理以及可能导致内存泄漏的原因。 首先,ThreadLocal是如何实现每个线程都有独立变量副本的呢?这主要得益于内部类`ThreadLocalMap`。当一个ThreadLocal对象被创建后,它并没有...

    实例详解Java中ThreadLocal内存泄露

    然而,如果不正确地使用ThreadLocal,可能会导致内存泄露,尤其是在Java EE容器如Tomcat中。本文将深入探讨这个问题,并提供解决方案。 在问题背景部分,我们看到一个示例,其中`LeakingServlet`类内部使用了一个...

    2、导致JVM内存泄露的ThreadLocal详解

    ### 导致JVM内存泄露的ThreadLocal详解 #### 一、为什么要有ThreadLocal 在多线程编程中,为了避免线程间的数据竞争和保证线程安全性,常常需要使用同步机制如`synchronized`来控制线程对共享资源的访问。然而,...

    关于java内存泄漏

    ### 关于Java内存泄漏 #### 一、Java内存管理机制 Java的一大特色在于其自动化的内存管理机制,这主要依赖于垃圾收集器(Garbage Collection, GC)来自动完成对象的内存分配与回收。尽管这一特性极大地减轻了...

    ThreadLocal应用示例及理解

    当线程结束时,与其关联的ThreadLocal变量不会自动清除,可能会导致内存泄漏。因此,推荐在不再使用ThreadLocal时显式调用`remove()`方法。 ```java threadLocal.remove(); ``` ### 示例:线程安全的计数器 假设...

    ThreadLocal

    - 内存泄漏:如果线程长时间存活,或者ThreadLocal对象没有被正确清理,可能导致ThreadLocalMap中的引用无法被垃圾回收,从而造成内存泄漏。 - 不适用于跨线程通信:ThreadLocal只保证同一线程内的数据隔离,不同...

    Java中ThreadLocal的设计与使用

    ### ThreadLocal内存泄漏问题 由于ThreadLocal变量是存储在线程的ThreadLocalMap中,如果线程长时间运行并且不清理ThreadLocal,当ThreadLocal对象被垃圾收集时,其在ThreadLocalMap中的引用将变为"幽灵引用"(弱...

    java中ThreadLocal详解

    需要注意的是,尽管使用了弱引用来避免内存泄漏,但仍需谨慎管理`ThreadLocal`实例的生命周期,确保及时释放不再使用的资源。此外,`ThreadLocalMap`通过开放地址法来解决哈希冲突,进一步提高了性能并减少了内存...

    JVM的基础和调优【JMM 内存结构 GC OOM 性能调优 ThreadLocal】

    内存泄露:是指程序在申请内存后,无法释放已申请的内存空间就造成了内存泄露, 一次的内存泄露似乎不会有大的影响,但是内存泄露堆积的后果就是内存溢出 JMM 决定一个线程对共享变量的写入何时对另一个线程可见,...

    ThreadLocal_ThreadLocal源码分析_

    Entry继承自WeakReference<ThreadLocal>,这意味着ThreadLocal对象如果不再被引用,可以被垃圾收集器回收,避免内存泄漏。然而,这种设计也存在一个问题:如果ThreadLocal没有被外部引用,但其对应的Entry还在Map中...

    threadLocal

    3. 内存管理:了解Java的内存模型和垃圾回收机制,才能理解ThreadLocal的内存泄漏风险和弱引用的作用。 4. HTTP相关:虽然题目中没有直接涉及,但HTTPClient是一个常见的网络通信工具,经常和ThreadLocal结合使用,...

    ThreadLocal原理及在多层架构中的应用

    - **内存泄漏风险**:如果不正确地使用ThreadLocal,如忘记清理ThreadLocal变量,可能导致内存泄漏。 - **线程隔离性**:ThreadLocal只在创建它的线程内有效,无法跨线程共享数据。 - **难以调试**:由于ThreadLocal...

    ThreadLocal整理.docx

    ThreadLocal 整理 ThreadLocal 是 Java 中... ThreadLocal 是 Java 中的一个重要组件,它能够在每个线程中保持独立的副本,解决 Hash 冲突的机制是通过斐波那契数来实现的,并且提供了扩容机制来避免内存泄漏的问题。

    Java系统中内存泄漏测试方法的研究

    4. ThreadLocal:如果线程局部变量未被正确清理,可能会导致内存泄漏。 5. 注册监听器未取消:注册的监听器如果没有在适当的时候解除注册,会持续持有对对象的引用。 四、内存泄漏的检测方法 1. **手动代码审查**...

Global site tag (gtag.js) - Google Analytics