ThreadLocal为什么要使用弱引用和内存泄露问题

在threadlocal的生命周期中,都存在这些引用. 看下图: 实线代表强引用,虚线代表弱引用.

下面来看两个问题:

1为什么要使用弱引用

2为什么会出现内存泄露问题


- 为什么要使用弱引用 - 

每个thread中都存在一个map, map的类型是ThreadLocal.ThreadLocalMap.

Map中的key为一个threadlocal实例. 这个Map的确使用了弱引用,不过弱引用只是针对key.

每个key都弱引用指向threadlocal.

所以当把threadlocal实例置为null以后,没有任何强引用指向threadlocal实例,所以threadlocal就可以顺利被gc回收

注意!假如每个key都强引用指向threadlocal,也就是上图虚线那里是个强引用,那么这个threadlocal就会因为和entry存在强引用无法被回收!造成内存泄漏 ,除非线程结束,线程被回收了,map也跟着回收。

- 依然出现的内存泄露问题 -

虽然上述的弱引用解决了key,也就是线程的ThreadLocal能及时被回收,但是value却依然存在内存泄漏的问题。

当把threadlocal实例置为null以后,没有任何强引用指向threadlocal实例,所以threadlocal将会被gc回收.

map里面的value却没有被回收.而这块value永远不会被访问到了. 所以存在着内存泄露,

因为存在一条从current thread连接过来的强引用.

只有当前thread结束以后, current thread就不会存在栈中,强引用断开, Current Thread, Map, value将全部被GC回收.

- 结论 -

所以当线程的某个localThread使用完了,马上调用threadlocal的remove方法,那就啥事没有了!

另外其实只要这个线程对象及时被gc回收,这个内存泄露问题影响不大,但在threadLocal设为null到线程结束中间这段时间不会被回收的,就发生了我们认为的内存泄露。
  
最要命的是线程对象不被回收的情况,这就发生了真正意义上的内存泄露。
比如使用线程池的时候,线程结束是不会销毁的,会再次使用的。就可能出现内存泄露。

- 补充说明 -

Java为了最小化减少内存泄露的可能性和影响,在ThreadLocal的get,set的时候都会清除线程Map里所有key为null的value。

所以最怕的情况就是:
threadLocal对象设null了,开始发生“内存泄露”,然后使用线程池,这个线程结束,线程放回线程池中不销毁,这个线程一直不被使用,或者分配使用了又不再调用get,set方法,那么这个期间就会发生真正的内存泄露。

推荐阅读:

详解 CQRS 架构模式

对 Kafka 和 Pulsar 进行性能测试后,拉卡拉将消息平台统一换成了 Pulsar

顺丰科技架构升级之路

聊聊数据库中的那些锁

浅谈Kafka中acks参数对消息持久化的影响

关注我

学习架构知识

互联网后端架构

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值