开发者社区> 1042238208560389> 正文

全面分析!ThreadLocal内存泄漏的原因!

简介: 全面分析!ThreadLocal内存泄漏的原因!
+关注继续查看

前言

ThreadLocal是一个大家都不陌生的对象,他的作用是能够进行跨方法的值传递,他的数据保存在线程中,每一个线程有一份单独的数据,我们可以用来来记录方法的执行时长等功能,但是使用他也会造成风险,比如会造成内存溢出,那么是什么情况下回有内存溢出的情况呢,下面我们就聊一聊

内存溢出原因

可能大部分的人都会说,是因为弱引用,因为弱引用时,gc会直接内存回收掉,那么引用的值就会为null,这一点其实我一直很困惑,如果弱引用直接内存回收掉,那么存在threadLocal里面的值不就没有了吗?那ThreadLocal使用起来风险不就会非常大,进行内存回收时数据不就丢失了吗?这是很严重的事故呀!!!

那为什么还在用呢?
一图胜前言

image.png
从图上可以看出来,其实ThreadLocal关联两个引用,在ThreadLcocal对象上是强引用,而在Entry对象上是弱引用,那么如果gc想回收,必须ThreadLocal对象本身不存在强引用,那什么时候ThreadLocal不存在强引用时,第一种Thead对象结束,我们知道Thread对象其实就是线程对象,他结束就意味着线程结束,线程结束内存被回收时没问题的。

但是还有一种,就是会产生内存泄漏的原因,就是在线程没结束时将ThreadLocal对象赋值为null,这意味着对象已经死亡,可以进行垃圾回收,这时ThreadLocal就不再存在强引用,而Entry对象引用的ThreadLocal由于是弱引用,也会被垃圾回收掉,而Value对象还存在Entry的强引用,value对象不会被垃圾回收,这就导致只要线程不结束,那Entry的key就为null,对应的value也就无法被访问,造成了内存泄漏,只有等线程结束才会被回收,因为在线程结束后,value才不会存在强引用,这里也解决了上面我提出的疑惑,数据丢失的问题,基于上面的分析,只要线程不结束,数据是不会丢失的。

除此之外,如果产生了内存泄漏,其实线程的存活时间比较短的话,影响程度一般不会很大,但是如果是在线程池中使用,就会产生较大的影响,因为线程池中的线程由于要重复利用,核心线程不会进入终止状态,这就意味着,线程会持续存货不会消亡,导致一直不被回收

ThreadLocal也提供了remove方法来方式来防止内存泄漏。我们看一下remove方法的实现


public void remove() {
    ThreadLocalMap m = getMap(Thread.currentThread());
    if (m != null)
        m.remove(this);
}

private void remove(ThreadLocal<?> key) {
    Entry[] tab = table;
    int len = tab.length;
    int i = key.threadLocalHashCode & (len-1);
    for (Entry e = tab[i];
         e != null;
         e = tab[i = nextIndex(i, len)]) {
        if (e.get() == key) {
            e.clear();
            expungeStaleEntry(i);
            return;
        }
    }
}

首先从想成中获取当前线程对应的ThreadLocalMap,然后判断如果不为空,就将Entry对象中的内存都移除掉,这里面就包含value对象,也就避免了内存泄漏。

ThreadLocal设置弱引用原因

从上面的分析,我们发现内存泄漏的一部分原因是由于,Entry对象的弱引用,但是为什么设置Entry引用的ThreadLocal对象为弱引用呢,其实将他设置成弱引用也是防止内存泄漏的,看到这里,一些读者可定会很困惑,内存泄漏的原因和他有关,但是为什么他却又是防止内存泄漏呢?

其实,ThreadLocal的内存泄漏可能分两种

  1. key内存泄漏
    这种内存泄漏我们是看不见的,为什么,就是因为将ThreadLocal使用弱引用才解决了这个问题,如果设计成强引用,这时我们在业务方法中将ThreadLocal设置为null,这时Entry对象中对ThreadLocal是强引用,就意味着ThreadLocal不是进行垃圾回收,直接导致了key的内存泄漏。
  2. value内存泄漏
    其实value的内存泄漏就是我们前面分析的内存泄漏,为了防止他发生,所以调用remove方法,除此之外,set和get方法也有将ThreadLocal为null的Enrty删除掉的逻辑,目的也就是处理这种情况

后记

ThreadLocal对象的内存溢出估计很多人都了解其原因,但是只有了解其存储结构才能更深刻的了解到他的泄漏原因,这个问题其实困惑了我很久,深挖之后还是有一定的收获的。

版权声明:本文内容由便宜云服务器实名注册用户自发贡献,版权归原作者所有,便宜云服务器开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《便宜云服务器开发者社区用户服务协议》和《便宜云服务器开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
ThreadLocal引用分析
ThreadLocal引用分析
30 0
来聊聊ThreadLocal内存泄露分析
? 前几天有个学生问我ThreadLocal存在不存在内存泄漏,趁此机会和大家聊聊ThreadLocal到底存在不存在内存泄漏以及怎么避免。 Thread中的threadLocals属性 一切都要从?Thread?的一个属性?threadLocals?说起,让我们看下这个属性的介绍: /* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null; 这个
78 0
ThreadLocal尾篇:ThreadLocal内存泄漏到底因为啥
ThreadLocal尾篇:ThreadLocal内存泄漏到底因为啥
69 0
ThreadLocal 你怎么动不动就内存泄漏?
如果说 ThreadLocal 的话,那肯定就会涉及到内存泄漏,为啥嘞 因为 吧啦吧啦 ~
88 0
ThreadLocal内存溢出代码演示和原因分析!(6)
ThreadLocal内存溢出代码演示和原因分析!(6)
55 0
ThreadLocal内存溢出代码演示和原因分析!(4)
ThreadLocal内存溢出代码演示和原因分析!(4)
60 0
ThreadLocal内存溢出代码演示和原因分析!(1)
ThreadLocal内存溢出代码演示和原因分析!(1)
72 0
ThreadLocal内存溢出代码演示和原因分析!(2)
ThreadLocal内存溢出代码演示和原因分析!(2)
58 0
ThreadLocal内存溢出代码演示和原因分析!(5)
ThreadLocal内存溢出代码演示和原因分析!(5)
74 0
Juc17_ThreadLocal概述、解决SimpleDateFormat出现的异常、内存泄漏、弱引用、remove方法(二)
②. 从阿里ThreadLocal规范开始 ①. 非线程安全的SimpleDateFormat ②. 将SimpleDateFormat定义成局部变量(方案一)
200 0
+关注
1042238208560389
文章
问答
视频
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载


http://www.vxiaotou.com