ThreadLocal 内存泄漏问题深刻分析

写在前面

ThreadLocal 基本用法本文就不介绍了,若是有不知道的小伙伴能够先了解一下,本文只研究 ThreadLocal 内存泄漏这一问题。数组

ThreadLocal 会发生内存泄漏吗?

先给出结论:若是你使用不当是有可能发生内存泄露的spa

<br/>线程

每一个 Thread 里面都有一个 ThreadLocalMap,而 ThreadLocalMap 中真正承载数据的是一个 Entry 数组,Entry 的 Key 是 threadlocal 对象的弱引用。对象

这里或许有的小伙伴有疑问,Entry 的 Key 是 threadlocal 对象的弱引用,为何要用弱引用,换成强引用行不行?blog

首先,咱们先了解一下什么是弱引用?内存

弱引用通常是用来描述非必需对象的,被弱引用关联的对象只能生存到下一次垃圾收集发生以前。 当垃圾收集器工做时,不管当前内存是否足够,都会回收掉只被弱引用关联的对象

实际开发中,当咱们不须要 threadlocal 后,为了 GC 将 threadlocal 变量置为 null,没有任何强引用指向堆中的 threadlocal 对象时,堆中的 threadlocal 对象将会被 GC 回收,假设如今 Key 持有的是 threadlocal 对象的强引用,若是当前线程仍然在运行,那么从当前线程一直到 threadlocal 对象仍是存在强引用,因为当前线程仍在运行的缘由致使 threadlocal 对象没法被 GC,这就发生了内存泄漏。相反,弱引用就不存在此问题,当栈中的 threadlocal 变量置为 null 后,堆中的 threadlocal 对象只有一个 Key 的弱引用关联,下一次 GC 的时候堆中的 threadlocal 对象就会被回收,使用弱引用对于 threadlocal 对象而言是不会发生内存泄漏的开发

那么,第二个问题来了,是否是 Key 持有的是 threadlocal 对象的弱引用就必定不会发生内存泄漏呢?rem

结论是:若是你使用不当仍是有可能发生内存泄露,可是,这里发生内存泄漏的地方和上面不一样。get

当 threadlocal 使用完后,将栈中的 threadlocal 变量置为 null,threadlocal 对象下一次 GC 会被回收,那么 Entry 中的与之关联的弱引用 key 就会变成 null,若是此时当前线程还在运行,那么 Entry 中的 key 为 null 的 Value 对象并不会被回收(存在强引用),这就发生了内存泄漏,固然这种内存泄漏分状况,若是当前线程执行完毕会被回收,那么 Value 天然也会被回收,可是若是使用的是线程池呢,线程跑完任务之后放回线程池(线程没有销毁,不会被回收),Value 会一直存在,这就发生了内存泄漏。it

如何更好的下降内存泄漏的风险呢?

ThreadLocal 为了下降内存泄露的可能性,在 set,get,remove 的时候都会清除此线程 ThreadLocalMap 里 Entry 数组中全部 Key 为 null 的 Value。因此,当前线程使用完 threadlocal 后,咱们能够经过调用 ThreadLocal 的 remove 方法进行清除从而下降内存泄漏的风险。

最后

若是你们想要实时关注我更新的文章以及我分享的干货的话,能够关注个人公众号 咱们都是小白鼠

相关文章
相关标签/搜索