赣州房产网站建设,win优化大师有免费版吗,seo优化技术排名,qq空间刷赞网站推广前几天看的小林coding的ThreadLocal为什么会导致内存泄漏#xff0c;但是没有看的太明白#xff0c;今天趁着有空#xff0c;来聊聊为什么ThreadLocal会导致内存泄漏
为什么会导致内存泄漏#xff1f;
弱引用的 ThreadLocal key 可能被回收#xff1a; 当程序中没有强引…前几天看的小林coding的ThreadLocal为什么会导致内存泄漏但是没有看的太明白今天趁着有空来聊聊为什么ThreadLocal会导致内存泄漏
为什么会导致内存泄漏
弱引用的 ThreadLocal key 可能被回收 当程序中没有强引用指向某个 ThreadLocal 实例时这个 ThreadLocal 对象会被 GC 回收因为它只被 ThreadLocalMap 的弱引用持有。
//可以看到是弱引用
static class Entry extends WeakReferenceThreadLocal? {/** The value associated with this ThreadLocal. */Object value;Entry(ThreadLocal? k, Object v) {super(k);value v;}}但是 ThreadLocalMap 中对应的 value 却是强引用被entry引用 value 是线程局部变量真正的对象实例是强引用GC 不会回收。
让我们进一步想为什么value是强引用当key被回收后value不是也没有人引用他了吗
1. ThreadLocalMap 结构简单理解
ThreadLocalMap 是一个特殊的哈希表里面的每个 Entry 是
static class Entry extends WeakReferenceThreadLocal? {Object value;
}key 是一个弱引用指向 ThreadLocal 对象。value 是普通的强引用指向对应线程变量的值。
2. key 被回收后Entry 中的 key 变成 null
当没有任何强引用指向这个 ThreadLocal 实例时GC 会回收这个 ThreadLocal 对象Entry 里的弱引用 key 就变成了 null。
3. 但是 Entry 对象本身和 value 对象还被谁引用
Entry 对象是存储在 ThreadLocalMap 的内部数组里。ThreadLocalMap 是线程Thread对象的一个成员变量线程对象一般是强引用线程还活着。也就是说整个 ThreadLocalMap 被线程强引用Entry 也被 ThreadLocalMap 强引用由于 Entry 本身还引用着 valuevalue 是普通强引用所以 value 依然是“可达”的。
4. 关键点value 被 Entry 强引用Entry 被 ThreadLocalMap 强引用ThreadLocalMap 被线程强引用
所以
线程对象强引用└─ ThreadLocalMap强引用└─ Entry强引用├─ key弱引用已回收变 null└─ value强引用value 因此不会被 GC 回收因为根可达路径依然存在。
5. 为什么会是“孤儿”
key 已经为 null没有办法再通过 ThreadLocal 找到它的 value也就是说这个 Entry 变成“垃圾”条目。
但这个垃圾条目没有被清理掉依然占用内存。
6. 什么时候 value 会被回收
线程结束ThreadLocalMap 和 Entry 都被回收。主动调用 ThreadLocal.remove() 清理 Entryvalue 的强引用断开。ThreadLocalMap 清理过期key null的 EntryJDK 会有清理机制但不一定马上执行。
总结 key 被回收后Entry 里的 key 为 null但 Entry 本身仍被 ThreadLocalMap 引用而 value 是 Entry 的普通强引用因此 value 依然可达不会被回收。 现在对threadLocal内存泄漏的原理是不是会清晰一点。