首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >threadlocal内存泄漏的原因

threadlocal内存泄漏的原因

作者头像
utopia
发布2023-03-21 11:01:09
1.2K0
发布2023-03-21 11:01:09
举报
文章被收录于专栏:UtopiaUtopia

ThreadLocal的原理:

ThreadLocal的set实际实在当前线程对象里创建了一个内部变量ThreadLocalMap<ThreadLocal,object> ,ThreadLocalMap的key是ThreadLocal的引用。

造成泄漏的原因:

由于ThreadLocal对象是弱引用,如果外部没有强引用指向它,它就会被GC回收,导致Entry的Key为null

如果当前的情况下在栈中将threadlocal1的引用设置为null,强引用1将会失效,那堆中的threadlocal1对象因为ThreadLocalMap的key对它的引用是弱引用,将会在下一次gc被回收,那就会出现key变成null,如果这时value外部也没有强引用指向它,那么value就永远也访问不到了,按理也应该被GC回收,但是由于ThreadLocalMap.Entry对象还在强引用value,导致value无法被回收,这时「内存泄漏」就发生了,value成了一个永远也无法被访问,但是又无法被回收的对象。

解决办法:

1:将ThreadLocal设置为空之前,执行remove()方法,会将key为空的键值对清空

2:尽量将ThreadLocal设置成static

3: 非必要尽量不要在ThreadLocal中放大对象

ThreadLocal做出的努力

ThreadLocal不是洪水猛兽,不要听到「内存泄漏」就不敢使用它,只要你规范化使用是不会有问题的。再者,就算你不规范使用,ThreadLocal也做出了很多努力来最大程度的帮你避免发生「内存泄漏」。

前面已经说过,由于Key是弱引用,因此ThreadLocal可以通过key.get()==null来判断Key是否已经被回收,如果Key被回收,就说明当前Entry是一个废弃的过期节点,ThreadLocal会自发的将其清理掉。

hreadLocal会在以下过程中清理过期节点:

调用set()方法时,采样清理、全量清理,扩容时还会继续检查。 调用get()方法,没有直接命中,向后环形查找时。 调用remove()时,除了清理当前Entry,还会向后继续清理。

为什么这里要用弱引用:

网上有的文章将ThreadLocal内存泄漏的原因怪罪于Entry的Key的弱引用,这个说法是极其错误的!

不用弱引用就能避免「内存泄漏」了吗?当然不是!!! 恰恰相反,使用弱引用是JDK在尽量避免程序出现「内存泄漏」,如下代码:

public class Test {
    public static void main(String[] args) {
        ThreadLocal threadLocal = new ThreadLocal();
        threadLocal.set(new Object());
        threadLocal = null;
    }
}

创建一个ThreadLocal对象,并设置一个Object对象,然后将其置空。如果Key不是弱引用的话,threadLocal无法被回收,也无法被访问,object无法被回收,也无法被访问,Key和Value同时出现了「内存泄漏」

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-03-01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ThreadLocal的原理:
  • 造成泄漏的原因:
  • 解决办法:
  • ThreadLocal做出的努力
  • 为什么这里要用弱引用:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档