ThreadLocalMap 中的 key 使用弱引用会出现内存泄漏吗

一 图解

回收前

回收后

二 图解说明

1 假设在业务代码中使用完 ThreadLocal,threadLocal Ref 被回收。

2 由于 ThreadLocalMap 只持有 ThreadLocal 的弱引用,没有任何强引用指向 threadLocal 实例,所以 threadLocal 就可以顺利被垃圾回收器回收,此时 entry 中的 key = null。

3 但是在没有手动删除 entry 以及 currentThread 依然运行的前提下,也存在强引用链 threadRdf > currentThread > threadLocalMap > entry > value,value 不会被回收,而这块的 value 永远不会被访问到, 导致 value 内存泄漏。

也就是说, ThreadLocalMap 中的 key 使用了弱引用,也有可能内存泄漏。

三 出现内存泄漏的真实原因

内存泄漏发生跟 ThreadLocalMap 中的 key 是否使用弱引用是没有关系的。

那内存泄漏的真正原因是什么呢?

从刚才的分析来看,发生内存泄漏有两个前提:

1 没有手动删除这个 entry

2 CurrentThread 依然运行

第一点好理解,只要在使用然 ThreadLocal,调用其 remove 方法删除对应的 Entry,就能避免内存泄漏。

第二点稍微复杂一点,由于 ThreadLocalMap 是 Thread 的一个属性,被当前线程所使用,所以生命周期跟 Thread 一样长,那么在使用完 ThreadLocal,如果当前 Thread 也随之执行结束,ThreadLocalMap 自然也会被垃圾回收器回收掉,从根源上避免了内存泄漏。

综上,ThreadLocal 内存泄漏的根源是:由于 ThreadLocalMap 的生命周期跟 Thread 一样长,如果没有手动删除对应 key,就会导致内存泄漏。

四 为什么使用弱引用

根据刚才的分析:无论 ThreadLocalMap 中的 key 使用哪种类型引用都无法完全避免内存泄漏,跟使用弱引用没有关系。

要避免内存泄漏有两种方式:

1 使用完 ThreadLocal,调用其 remove 方法删除对应的 Entry。

2 使用完 ThreadLocal,当前 Thread 也随之运行结束。

相对第一种方式,第二种方式显然更不好控制,特别是使用线程池的时候,线程结束时不会被销毁的。

也就是说,只要记得在使用完 ThreadLocal,及时的调用 remove,无论 key 是强引用还是弱引用都不会有问题。那么为什么 key 要用弱引用呢?

事实上,在 ThreadLocalMap 中的 set/getEntry 方法中,会对 key 为 null(也就是 ThreadLocal 为 null )进行判断,如果为 null 的话,那么会对 value 置为 null 的。随后对应的 value 对象就会被垃圾回收。

这就意味着使用完 ThreadLocal,CurrentThread 依然运行的情况下,就算忘记调用 remove 方法,弱引用比强引用可以多一层保障:弱引用使用的 ThreadLocal 会被回收,对应的 value 在下一次 ThreadLocalMap 调用 set/getEntry/remove 的任何一个方法的时候会被清除,从而避免内存泄漏。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值