ThreadLocal以及内存泄露原理的源码解析

发布于:2025-06-20 ⋅ 阅读:(17) ⋅ 点赞:(0)

1. 什么是 Reference

Reference 是 Java 中处理引用类型的基类(在 java.lang.ref 包中)。它有四个直接子类,代表四种引用强度:

  • 强引用 (Strong Reference):普通的对象引用(Object obj = new Object()),只要存在强引用,对象就不会被 GC 回收

  • 软引用 (SoftReference):内存不足时会被 GC 回收

  • 弱引用 (WeakReference):只要发生 GC,就会被回收(即使内存充足)

  • 虚引用 (PhantomReference):用于对象回收跟踪

2.关于ThreadLocal的源码解析:

1.源码的五步解析:

图看不清楚的访问这里:图片

首先最重要的就是弱引用什么时候被回收?以及他的字段reference:

当发生 GC 时,如果某个对象  被 WeakReference 引用(没有强引用指向它),那么:

  1. 这个对象的referent 字段会被自动设为 null

  2. 被引用的对象会被回收

2.注意:这里的魔法

  1. 当 Entry 调用 super(k) 时:

    • 它调用了父类 WeakReference 的构造函数

    • k (ThreadLocal 对象) 被存入继承自 Reference 的 referent 字段

  2. 这个 referent 就是 Key 的存储位置!

    • 虽然 Entry 类没有显式声明 key 字段,但通过继承,它拥有了 referent 字段(来自 WeakReference → Reference)

    • 这个字段就是用来存储 Key (ThreadLocal 对象)的

3.魔法的实现原理----JVM

  1. WeakReference 类的魔法在 JVM 层面实现

    • 当 JVM 进行垃圾回收时,会特殊处理 WeakReference 及其子类的 referent 字段

    • 这个字段的值会被垃圾回收器特殊标记为弱引用

    • 这不是普通的 Java 继承特性,而是 JVM 对 Reference 类族的特殊处理

4.大概这么说:

首先要了解弱引用的法则:当发生 GC 时,如果某个对象  被 WeakReference 引用(没有强引用指向它),那么:这个对象的referent 字段会被自动设为 null,被引用的对象会被回收。

然后这个Entry继承了WeakReference ,并且ThreadLocal是被Reference的字段Referent引用着,因此被JVM标记为弱引用。。。当强引用消失后ThreadLocal引用的对象就会被回收。

我们的Thread对象最终被referent引用着

5.总结:

- `Entry`的key是通过继承自`WeakReference`的`referent`字段来存储的,并且是弱引用。

- `Entry`的value是通过自己的`value`字段存储,是强引用。

这样设计的主要目的是为了避免内存泄漏:当`ThreadLocal`对象(key)不再被其他地方强引用时,垃圾收集器可以回收这个key,这样`Entry`中的`referent`字段就会变成`null`。

虽然此时`Entry`和`value`还存在(因为`value`是强引用),但`ThreadLocalMap`在后续操作(如get、set、remove)时会自动清理这些key为null的`Entry`,从而避免value的内存泄漏。

最后:

  1. 强引用 Value: Entry 对 Value 持有强引用,确保只要 Entry 还在 Map 中,Value 就不会被 GC 回收。这是业务逻辑需要的。
  2. ThreadLocalMap 的设计包含了清理机制: 在调用 ThreadLocal 的 get()set()remove() 方法时,Map 会主动去扫描那些 Entry.get() == null (即 Key 已被回收) 的 Entry,并将这些 Entry 以及它们对应的强引用 Value 清除掉 (value = null),然后移除这些 Entry。所以我们一般都要显示的调用remove方法

网站公告

今日签到

点亮在社区的每一天
去签到