ThreadLocal为什么会产生内存泄漏?
1. ThreadLocal 的结构ThreadLocal 的内存泄漏问题和其内部存储结构紧密相关。每个 Thread 对象内部都有一个 ThreadLocalMap ThreadLocalMap 里维护着一个Entry[]哈希表每个Entry节点里面存着一对key与value。Entry节点里的key是弱引用key值里存的值指向的是ThreadLocal对象而Entry节点里的value是普通的强引用赋值是把你自己存进去的值放进去。所以即这个 ThreadLocalMap 的key 是 ThreadLocal 弱引用是实例本身value强引用是我们本身设置的。2. 强弱引用强引用强引用是一种在语法上默认采用的引用比如新new出一个任意的对象只要该对象变量不为null就是持有强引用的。持有强引用的变量无论内存够不够只要不为null都不会被GC垃圾回收。弱引用弱引用是一个WeakReference类WeakReference类创建出来的对象都是弱引用。只被弱引用指向的对象如果被GC垃圾收集器扫描到之后无论此时内存够不够该对象都会成为被回收的垃圾对象会被回收。3. 线程的复用线程复用是 ThreadLocal 内存泄漏很大的问题尤其是在我们实际创建线程时使用的都是线程池使用线程池线程必然会复用。4. ThreadLocal 内存泄漏的原因综上三点的基础我们会发现因为ThreadLocalMap的Entry节点里的key是弱引用value是强引用所以在线程池里一个线程完成线程任务后该线程可能还会被复用所以上一个线程任务的相关值要被清除但是因为key是弱引用会被回收而value是强引用不会被回收并且指向value的key已经被回收value不会再被访问到所以没有办法清除干净会有上一个线程任务的value还被这个线程持有占着内存发生内存泄露。5. 如何避免 ThreadLocal 内存泄漏1.被动清除阅读源码我们会发现set()方法和get()方法内部都内置了考虑会有残留value遗留的问题。所以只要调用get()、set()方法就会有被动清理的可能。2.主动清除可以调用remove()方法即可清除掉这个ThreadLocalMap的Entry[]中的这个Entry节点。