ThreadLocal 结构
1: ThreadLocal 本质是一个工具类,所set的对象并不存在ThreadLocal 对象中。
2: ThreadLocal 操作的本质是对Thread的成员变量,操作ThreadLocal.ThreadLocalMap threadLocals
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null; 、
inherit initial values for inheritable thread-locals from the constructing thread
所以通过MAT工具来看,一个线程有两个ThreadLocal.ThreadLocalMap 对象。
3: ThreadLocal.ThreadLocalMap 会有多个 java.lang.ThreadLocal$ThreadLocalMap$Entry 实体。
java.lang.ThreadLocal$ThreadLocalMap$Entry 的key是 ThreadLocal , Value是值。 如果
ThreadLocal 被置为空的话,因为java.lang.ThreadLocal$ThreadLocalMap 还持有对象
4: java.lang.ThreadLocal$ThreadLocalMap$Entry 可能导致内存泄露。除非线程消亡。
ThreadLocal 内存泄漏的原因
从上图中可以看出,hreadLocalMap使用ThreadLocal的弱引用作为key,如果一个ThreadLocal不存在外部强引用时,Key(ThreadLocal)势必会被GC回收,这样就会导致ThreadLocalMap中key为null, 而value还存在着强引用,只有thead线程退出以后,value的强引用链条才会断掉。
但如果当前线程再迟迟不结束的话,这些key为null的Entry的value就会一直存在一条强引用链:
Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value
打断这个引用键的方式 set(),get(),remove(),是做要对这个ThreadLocal不操作的话,不会触发对value的回收。
那为什么使用弱引用而不是强
当ThreadLocalMap的key为强引用回收ThreadLocal时,因为ThreadLocalMap还持有ThreadLocal的强引用,如果没有手动删除,ThreadLocal不会被回收,导致Entry内存泄漏。
key 使用强引用
当hreadLocalMap的key为强引用回收ThreadLocal时,因为ThreadLocalMap还持有ThreadLocal的强引用,如果没有手动删除,ThreadLocal不会被回收,导致Entry内存泄漏。 譬如 设置:ThreadLocal=null 以后,应该会被回收的,但实际情况是ThreadLocalMap还有一个强引用,导致无法回收
key 使用弱引用
当ThreadLocalMap的key为弱引用回收ThreadLocal时,由于ThreadLocalMap持有ThreadLocal的弱引用,即使没有手动删除,ThreadLocal也会被回收。当key为null,在下一次ThreadLocalMap调用set(),get(),remove()方法的时候会被清除value值。
譬如 设置:ThreadLocal=null 以后,强引用已没有,ThreadLocalMap还有一个弱引用,下次GC就会被回收