Java - 为什么 ThreadLocal 会导致内存泄漏

ThreadLocal 里面存储的数据,它的生命周期是和线程或者线程池的生命周期保持一致的,如果在整个程序的运行期间,线程和线程池都没有销毁的情况下,那么 ThreadLocal 里面的数据也不会被销毁,也不会被垃圾回收器所回收,这个就是内存泄露问题。当程序中有大量的数据,并且 ThreadLocal 里面所记录的都是大数据的情况下,那么持续的内存泄漏就有可能会造成内存溢出(OutOfMemory)。

 

Thread 源码中,每个线程 Thread 都拥有一个数据存储存储容器 ThreadLocalMap,在执行 ThreadLocal.set 方法的时候,会将存储的值放到 ThreadLocalMap 容器中,ThreadLocalMap 中有一个 Entry[] 数组用来存储所有的数据,此处的 Entry[] 可以理解为哈希桶。

Thread -> ThreadLocalMap -> Entry -> key,Value

引用类型分为 4 种 :强引用、软引用、弱引用、虚引用(几乎不用)

  • 强引用无法被 GC 回收
  • 软引用一般不会被 GC 回收,除非内存不够用了,触发了 full GC 了,那么才可能会回收软引用。
  • 弱引用会被 GC 回收

 为什么是一直持有 value ?

因为 ThreadLocal 在设计的时候,Entry 中的 key 使用的是弱引用,而 value 使用的是强引用。

        如果 ThreadLocal 没有被直接引用(外部强引用),那么在垃圾回收的时候,由于 ThreadLocalMap 中的 key 是弱引用,所以 key 一定会被回收,因此 ThreadLocalMap 中就会出现 key 为 null 的 Entry,并且没有办法访问这些数据,那么强引用链 Thread -> ThreadLocalMap -> Entry -> value 就会一直存在,导致 value 无法被 GC 回收,从而导致内存泄漏。

为什么 ThreadLocal 在设计的时候,Entry 中的 key 使用弱引用,value 使用强引用 ?

这是从 ThreadLocal 的性能和防止内存溢出这两方面综合考量的,如果说程序后面还需要使用 ThreadLocalMap,那么当插入的键值对的 value 已经存在时,就不需要重新进行插入了,只需要恢复当前键值对的 key 即可。

如何解决 ThreadLocal 内存泄漏问题 ??

只需要在使用完 ThreadLocal 之后,调用它的 remove 方法就可以避免内存泄漏问题了。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值