在网上关于ThreadLocal的内存泄漏有很多说法,这个问题本身也是一个比较热门的面试题。因此笔者在研究一番后将自己的心得总结如下。
首先必须说明的是,ThreadLocal一般情况下根本不会发生内存泄漏。其内存泄漏只会发生在一种情况下,ThreadLocal作为一个方法局部变量,随着线程结束被回收了,而且在该线程中使用到ThreadLocal的地方根本没有调用过remove方法。
ThreadLocal只是一个入口,这个类本身不维护那些线程私有的数据,其内部有一个静态内部类ThreadLocalMap,其内部有一个数据结构Entry数组,Entry数组才是真正存储数据的地方。Entry节点包括k v键值对,k是ThreadLocal,v则是我们要储存的数据。
调用remove方法时,会通过hash找到key,也就是threadlocal对应的下标,然后一直向下一直找到数组末尾,期间任何entry的k为这个threadlocal的,都将被清除。
threadlocal内存泄漏这个问题最常见的说法就是由于key为null(也就是threadlocal被回收了),导致即使在remove的时候找不到它对应的数据,从而无法清除v,进而发生内存泄漏。
然而作为k的threadlocal是强引用类型,想要它为null,只有一种可能性,它不可达了。简单的说它的具体场景就是它是在方法内部创建的一个局部变量,线程结束,虚拟机栈清空,其中的栈帧中维护的本地变量表的数据(方法中创建的threadlocal)随之被回收,只有这种场景才会发生threadlocal已经不可达,进而被回收的情况(假设threadlocal没有发生逃逸)。
以我的看法,threadlocal常用的场景是我们把它作为一个静态变量放到类中,而类的静态变量,是属于Class对象的,是一个随着整个容器生命周期的class对象的变量,是一直被引用着的,因此不会发生threadlocal被回收的情况,当然也无法发生对应的内存泄露的情况。
所以想要发生ThreadLocal内存泄漏的情况,必须要是作为局部变量,而且这个线程用的时候还没remove过。这样的情况想必很少见,并非没remove就会内存泄漏。
以上是我的浅见,欢迎各位大佬批评指正。