前言
探究 ThreadLocal 内存泄漏问题
弱引用: 每次 GC 都会回收
测试代码
package test;
import java.lang.ref.WeakReference;
public class WeakReferenceTest {
public static void main(String[] args) {
// 弱引用 this.referent指向引用对象
WeakReference<byte[]> weakReference = new WeakReference<>(new byte[10]);
System.out.println(weakReference.get());
// gc,回收弱引用
System.gc();
// null
System.out.println(weakReference.get());
/**
* ThreadLocal中的弱引用
* ThreadLocal中的ThreadLocalMap的Entry节点继承自WeakReference
*/
ThreadLocal<Integer> t1 = new ThreadLocal<Integer>();
System.out.println(t1);
Integer i1 = 134;
t1.set(i1);
// 置空,gc回收new ThreadLocal对象(该对象也被WeakReference引用)
t1 = null;
// t1.remove();
// 查看Thread类的threadLocals的Entry节点
Thread thread = Thread.currentThread();
System.out.println("thread = " + thread);
System.gc();
// 再次查看Thread类的threadLocals的Entry节点,弱引用被gc
System.out.println("gc()...");
}
}
debug 测试代码
查看 thread 对象中 referent 的变化
执行 System.gc()
后, referent 对象被置为 null ,但是 value 值仍在。
value 值还存在
下面截取 TreadLocal 中源码
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
说明:Entry 继承了 WeakReference,但是调用了super传递的是 t1 这个对象。
t1两处引用,一个t1 = new,一个被弱引用了。
t1=null,然后t1就只有被弱引用,调用gc , t1 也被回收了
然后value这个就再也访问不到了,也清除不了。
参考
ThreadLocal内存泄漏问题
弱引用WeakReference作用与使用场景
一个场景Demo分析ThreadLocal使用方法和原理