1. 内存泄漏
      内存溢出: Memory overflow 没有足够的内存提供申请者使用.
      内存泄漏: Memory Leak 程序中已经动态分配的堆内存由于某种原因,程序未释放或者无法释放,造成系统内部的浪费 , 导致程序运行速度减缓甚至系统崩溃等严重结果。内存泄漏的堆积终将导致内存溢出
    2. key=ThreadLocal 是强引用
      假设 ThreadLocalMap 中的 key 使用了强引用 , 那么会出现内存泄漏吗?

    假设在业务代码中使用完 ThreadLocal, ThreadLocal ref 被回收了
    但是因为 threadLocalMap 的 Entry 强引用了 threadLocal (key 就是 threadLocal), 造成 ThreadLocal 无法被回收
    在没有手动删除 Entry 以及 CurrentThread (当前线程) 依然运行的前提下,始终有强引用链CurrentThread Ref → CurrentThread →Map(ThreadLocalMap)-> entry, Entry 就不会被回收 (Entry 中包括了 ThreadLocal 实例和 value), 导致 Entry 内存泄漏
    也就是说: ThreadLocalMap 中的 key使用了强引用, 是无法完全避免内存泄漏的

    1. key=ThreadLocal 是弱引用
      假设 ThreadLocalMap 中的 key 使用了弱引用 , 那么会出现内存泄漏吗?

    假设在业务代码中使用完 ThreadLocal, ThreadLocal ref 被回收了
    由于 threadLocalMap 只持有 ThreadLocal 的弱引用 , 没有任何强引用指向 threadlocal 实例(这里 Entry 不再强引用 ThreadLocal 了), 所以 threadlocal 就可以顺利被 gc 回收,此时 Entry 中的 key = null
    在没有手动删除 Entry 以及 CurrentThread 依然运行的前提下,也存在始终有强引用链CurrentThread Ref → CurrentThread →Map(ThreadLocalMap)-> entry,value 就不会被回收,而这块 value 永远不会被访问到了(因为 key=null), 导致 value 内存泄漏
    也就是说: ThreadLocalMap中的key使用了弱引用, 也有可能内存泄漏

    1. 内存泄漏的真实原因

    比较以上两种情况,我们就会发现:
    内存泄漏的发生跟 ThreadLocalIMap 中的 key 是否使用弱引用是没有关系的。那么内存泄漏的的真正原因是什么呢?

    细心的同学会发现,在以上两种内存泄漏的情况中.都有两个前提:主要两个原因
    1 . 没有手动侧除这个 Entry
    2 . CurrentThread 当前线程依然运行

    第一点很好理解,只要在使用完下 ThreadLocal ,调用其 remove 方法删除对应的 Entry ,就能避免内存泄漏。
    第二点稍微复杂一点,由于 ThreadLocalMap 是 Thread 的一个属性,被当前线程所引用,所以 ThreadLocalMap 的生命周期跟 Thread 一样长。那么在使用完 ThreadLocal 的使用,如果当前 Thread 也随之执行结束, ThreadLocalMap 自然也会被 gc 回收,从根源上避免了内存泄漏。
    综上, ThreadLocal 内存泄漏的根源是:
    由于 ThreadLocalMap 的生命周期跟 Thread 一样长,如果没有手动删除(remove () 方法)对应 key 就会导致内存泄漏.

    1. key 要使用弱引用
      为什么使用弱引用,根据刚才的分析,我们知道了:

    无论 ThreadLocalMap 中的 key 使用哪种类型引用都无法完全避免内存泄漏,跟使用弱引用没有关系。

    要避免内存泄漏有两种方式:

    1 .使用完 ThreadLocal ,调用其 remove 方法删除对应的 Entry
    2 .使用完 ThreadLocal ,当前 Thread 也随之运行结束
    相对第一种方式,第二种方式显然更不好控制,特别是使用线程池的时候,线程结束是不会销毁的.

    也就是说,只要记得在使用完 ThreadLocal 及时的调用 remove ,无论 key 是强引用还是弱引用都不会有问题.

    那么为什么 key 要用弱引用呢

    事实上,在 ThreadLocalMap 中的set/getEntry 方法中,会对 key 为 null(也即是 ThreadLocal 为 null )进行判断,如果为 null 的话,那么会把 value 置为 null 的.

    这就意味着使用完 ThreadLocal , CurrentThread 依然运行的前提下.就算忘记调用 remove 方法,弱引用比强引用可以多一层保障:弱引用的 ThreadLocal 会被回收.对应 value 在下一次 ThreadLocaIMap 调用 set/get/remove 中的任一方法的时候会被清除,从而避免内存泄漏.
    ————————————————
    版权声明:本文为CSDN博主「JH灰色」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/JH39456194/article/details/107304997