关于ThreadLocal,为什么会导致内存泄漏?

在这里插入图片描述

首先来看ThreadLocal中的源码,这是ThreadLocal中的set方法

它首先通过Thread.currentThread()方法去获取当前线程,然后将当前线程t传到getMap方法里面。

在这里插入图片描述

跟进去getMap方法之后我们发现,t.threadLocals调用的是其实线程Thread类里面的一个局部变量ThreadLocal.ThreadLocalMap。

在这里插入图片描述
也就是说每个Thread线程都有自己独有的一个Map叫ThreadLocalMap,这也就是为什么ThreadLocal能保证线程互不干扰的原因。因为每个Thread线程操作的只是自己的Map。

再返回去看ThreadLocals的set方法,一开始Thread里面的ThreadLocalMap属性是为null的,那么它就通过createMap()方法去创建一个线程独有的ThreadLocalMap。

那么我们再跟进来看看这个创建的这个ThreadLocalMap有什么秘密吧。
在这里插入图片描述
在这里插入图片描述

这段代码的逻辑最终作用是——把该ThreadLocal对应的值存在一个成员变量table里,以key/value的形式存储,key是当前的ThreadLocal实例,value就是我们要保存的值

我们发现,ThreadLocalMap创建的时候,创建的Entry继承了弱引用。

在这里插入图片描述

弱引用的特点就是只有有GC,不管内存够不够它都会被GC所回收

类型回收时间应用场景
强引用一直存活,除非GC Roots不可达所有程序的场景,基本对象,自定义对象等
软引用内存不足时会被回收一般用在对内存非常敏感的资源上,用作缓存的场景比较多,例如:网页缓存、图片缓存
弱引用只能存活到下一次GC前生命周期很短的对象,例如ThreadLocal中的Key。
虚引用随时会被回收, 创建了可能很快就会被回收可能被JVM团队内部用来跟踪JVM的垃圾回收活动

之所以不使用其他的强引用,软引用等,是因为:

强引用,即使key为null,但key的引用依然指向ThreadLocal对象,所以会发生内存泄漏。

软引用是内存不够才会被GC回收,它更适合缓存的使用场景。

虚引用是用来管理直接内存GC的。

只要你了解了弱引用的概念,那么就会知道,原来ThreadLocal发生内存泄漏的原因就是在这里了。

因为ThreadLocal被回收后,key为null,导致value再也无法被访问,那怎么办呢?只能是把整个entry给remove掉,而不是仅仅回收key。事实上,ThreadLocal在调用set()和get()方法时会自动remove掉key为null的entry。但是如果不执行set()和get()就会存在泄漏。所以我们要养成手动remove的习惯

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值