关于ThreadLocal的使用可能造成的内存泄露以及避免方案以及为什么使用弱引用

我们知道,每个Thread类中有一个ThreadLocalMap类型的threadLocals变量,即每个线程中都有一个自己的map,map中的key为ThreadLocal实例,value为要存储的值
关于ThreadLocal的使用可能造成的内存泄露以及避免方案以及为什么使用弱引用_第1张图片
我们查看该Map的结构,发现里面有个内部类Entry,此Entry类型是构成map的结点结构,类似HashMap中的Node一样。
关于ThreadLocal的使用可能造成的内存泄露以及避免方案以及为什么使用弱引用_第2张图片
我们在此发现一个问题,发现Entry中的key没有显式声明,是一个ThreadLocal弱类型的引用,初始化依赖于WeakReference类,为什么Entry中的key要设计成弱类型的呢?

原因是:key不是弱引用将可能产生内存泄露,现在假设key设计成了强引用,在我们日常使用时,当当前类中Threadlocal类型不用时,理应会赋null,然后会被GC,但是由于thread中有的Entry类中key有强引用指向Threadlocal对象,所以该对象不会被回收,就造成了内存泄露,内存泄露是指本应该被回收的对象没有被回收。

key设计成弱引用将帮助回收Entry中的key,因为此时一但当前类中的强引用没了,手动赋空或者类被销毁,Threadlocal对象因为是弱引用即将就会被gc,避免了key被无法回收的内存泄露情况,但是此时value没有回收,还可能会造成内存泄露,JDK8中ThreadLocal为了避免内存泄露通过 set,get,remove方法把key为null的Entry清理掉。

使用Threadlocal时还要注意,在配合线程池使用时,不及时remove会造成内存泄露,因为线程池中的线程始终不销毁,单个ThreadLocal实例,在n个线程中会存在n个map,对应n个Entry,如果不及时采用remove在使用完之后移除key,将可能造成内存溢出。

所以总结出来,在使用ThreadLocal时,如果可预知的知道ThreadLocal在什么时候不会使用时,要及时调用remove方法移除。

你可能感兴趣的:(JAVA,后端)