前言

ThreadLocal是一个咱们都不生疏的目标,他的作用是能够进行跨办法的值传递,他的数据保存在线程中,每一个线程有一份单独的数据,咱们能够用来来记载办法的执行时长等功能,可是运用他也会形成风险,比如会形成内存溢出,那么是什么状况下回有内存溢出的状况呢,下面咱们就聊一聊

内存溢出原因

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

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

全面分析!ThreadLocal内存泄漏的原因!
从图上能够看出来,其实ThreadLocal关联两个引证,在ThreadLcocal目标上是强引证,而在Entry目标上是弱引证,那么假如gc想收回,必须ThreadLocal目标自身不存在强引证,那什么时候ThreadLocal不存在强引证时,第一种Thead目标完毕,咱们知道Thread目标其实便是线程目标,他完毕就意味着线程完毕,线程完毕内存被收回时没问题的。

可是还有一种,便是会产生内存走漏的原因,便是在线程没完毕时将ThreadLocal目标赋值为null,这意味着目标已经逝世,能够进行废物收回,这时ThreadLocal就不再存在强引证,而Entry目标引证的ThreadLocal因为是弱引证,也会被废物收回掉,而Value目标还存在Entry的强引证,value目标不会被废物收回,这就导致只要线程不完毕,那Entry的key就为null,对应的value也就无法被拜访,形成了内存走漏,只有等线程完毕才会被收回,因为在线程完毕后,value才不会存在强引证,这儿也处理了上面我提出的疑惑,数据丢掉的问题,基于上面的分析,当ThreadLocal设置成null才会出问题,正常状况下咱们也不会通过null去查数据,所以不存在数据丢掉问题。

除此之外,假如产生了内存走漏,其实线程的存活时间比较短的话,影响程度一般不会很大,可是假如是在线程池中运用,就会产生较大的影响,因为线程池中的线程因为要重复运用,中心线程不会进入停止状态,这就意味着,线程会继续存货不会消亡,导致一向不被收回

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目标的内存溢出估量很多人都了解其原因,可是只有了解其存储结构才干更深入的了解到他的走漏原因,这个问题其实困惑了我很久,深挖之后仍是有必定的收成的。