ThreadLocal内存泄漏问题
ThreadLocal内存泄漏问题
内存泄漏:
不再会被使用的对象或者变量占用的内存不能被回收,就是内存泄漏
为什么要用弱引用?
- 为什么要用弱引用:
-
- 当方法执行完毕后,栈帧销毁,强引用t1也就没有了,但此时线程的ThreadLocalMap里某个entry的Key引用还指向这个对象,若这个Key是强引用,就会导致Key指向的ThreadLocal对象即V指向的对象不能被gc回收,造成内存泄露
- 若这个引用时弱引用就大概率会减少内存泄漏的问题(当然,还得考虑key为null这个坑),使用弱引用就可以使ThreadLocal对象在方法执行完毕后顺利被回收且entry的key引用指向为null
- 这里有个需要注意的问题:
-
- ThreadLocalMap使用ThreadLocal的弱引用作为Key,如果一个ThreadLocal没有外部强引用引用他,那么系统gc时,这个ThreadLocal势必会被回收,这样一来,ThreadLocalMap中就会出现Key为null的Entry,就没有办法访问这些Key为null的Entry的value,如果当前线程迟迟不结束的话(好比正在使用线程池),这些key为null的Entry的value就会一直存在一条强引用链
- 虽然弱引用,保证了Key指向的ThreadLocal对象能够被及时回收,但是v指向的value对象是需要ThreadLocalMap调用get、set时发现key为null时才会去回收整个entry、value,因此弱引用不能100%保证内存不泄露,我们要在不使用某个ThreadLocal对象后,手动调用remove方法来删除它,尤其是在线程池中,不仅仅是内存泄漏的问题,因为线程池中的线程是重复使用的,意味着这个线程的ThreadLocalMap对象也是重复使用的,如果我们不手动调用remove方法,那么后面的线程就有可能获取到上个线程遗留下来的value值,造成bug。
- 清除脏Entry----key为null的entry
- 这里使用强引用会如何:
在使用线程池的任务中,如果使用完线程后,业务代码中强引用ThreadLocal的对象就没有了,而此时ThreadLocalMap中键值对的Key(ThreadLocal)还是在引用它,如果这个引用是强引用,呢么此时这个线程的ThreadLocalMap中的数据就不会被清理了(因为ThreadLocal
实例无法被 GC 回收),但这些数据存在已经没有意义了,从而造成内存泄漏
情况一:
主线程和短生命周期线程:
●对于主线程或临时创建的线程,线程的生命周期结束后,线程的所有对象,包括 ThreadLocalMap,都会被回收,所以通常不会造成内存泄漏
情况二:
线程池中的线程:
●线程池中的线程长期存在,不会因为任务结束而被回收。如果在任务中使用了 ThreadLocal,但没有清理(调用 remove()),对应的值会一直保留在
ThreadLocalMap 中,导致内存泄漏。
为什么线程池特别容易出现内存泄漏?
1.线程重用:
线程池中的线程不会随着任务完成而销毁,ThreadLocalMap 也不会自动清空。
2.弱引用的作用有限:
ThreadLocal 在 ThreadLocalMap 中是弱引用,但其值(value)是强引用。即使 ThreadLocal
被垃圾回收,ThreadLocalMap 的条目不会立即清除,其 value 仍然占用内存,需通过 remove () 主动释放。

浙公网安备 33010602011771号