原文链接:ThreadLocal为什么会出现内存泄漏,你真的知道吗? – 编程屋
目录
1 前言
大家想要搞清楚这个问题,就必须知道内存泄漏和内存溢出的区别
内存泄漏:不就被使用的对象或者变量无法被回收
内存溢出:没有剩余的空间来创建新的对象
2 ThreadLocal进行线程隔离的小示例
同一个threadlocal对象,不同线程之间存储的值是获取不到的
public class QuThreadLocal {
static ThreadLocal<Wolf> t1 = new ThreadLocal<>();
public static void main(String[] args) {
new Thread(()->{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
t1.set(new Wolf("小王"));
System.out.println(t1.get());
t1.remove();
}).start();
new Thread(()->{
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t1.get());
}).start();
}
}
控制台输出:
可以发现在不同的线程里面放置东西,其它线程里面是找不到的。
解析原因,观察是如何向threadlocal中放置值的:
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
1)先获取当前线程t,然后根据t获取threadmap对象
2)判断map是否为null,map不为null时,将当前threadllocal对象作为key,想要设置的值作为value放置其中,否则就创建一个map。创建map的key值与上相同。
这也表明了,存储的值只有当前线程才能够获取到。
3 原因
threadlocal内部结构:
造成内存泄漏的原因:
由于Entry中的value是强引用,key是弱引用;当垃圾回收器回收threadlocal时,由于value是强引用,不能被回收,所以造成了内存泄漏。
因此,ThreadLocal内存泄漏的根源是:由于ThreadLocalMap的生命周期跟Thread一样长,如果没有手动删除对应的key就会导致内存泄漏,而并不是因为弱引用。
解决方案一:扩大成员变量Threadlocal的一个作用域,避免被GC回收(不推荐)
解决方案二:每次使用完threadlocal之后,就调用remove方法去移除对应的数据(推荐)
以上只是部分内容,为了维护方便,本文已迁移到新地址:ThreadLocal为什么会出现内存泄漏,你真的知道吗? – 编程屋