ThreadLocal内存泄漏
ThreadLocal内存泄漏
- ThreadLocal内存泄漏是指由于ThreadLocal的使用不当,导致线程结束后其关联的ThreadLocal变量无法被垃圾回收,从而引发内存泄漏问题。
1. 内存泄漏原因
-
ThreadLocal内存泄漏的根本原因在于其内部实现机制 -
ThreadLocalMap的Entry定义如下:1
2
3
4
5
6
7
8static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
} -
其中:
key(ThreadLocal 对象)是“弱引用”,也就是把ThreadLocal对象给丢了,JVM下轮GC就能把key给回收掉。value是“强引用”,也就是只要Thread对象还在,value就不会被回收掉。
-
当
key被GC回收掉后,Map里会出现key为null,但value不为null的情况,理想情况下,下次访问ThreadLocal或set/remove时,ThreadLocalMap会扫描并清理这些“僵尸key”,但是如果不在使用这个ThreadLocal,那么清理逻辑就永远不会触发,就会导致内存泄漏问题。 -
内存泄漏的发生需要同时满足两个条件:
ThreadLocal实例不再被强引用- 线程持续活动,导致
ThreadLocalMap长期存在
2. 如何避免内存泄漏的发生
- 如何避免内存泄漏:
- 使用完
ThreadLocal后及时调用remove()方法。remove()方法会从ThreadLocalMap中显示地移除对应的entry,从而避免内存泄漏问题。 - 在线程池等线程复用的场景下,使用
try-finally块可以确保即使发生异常,remove()方法也一定会被执行1
2
3
4
5
6
7
8ThreadLocal<MyObject> threadLocal = new ThreadLocal<>();
try {
threadLocal.set(new MyObject());
// 使用 threadLocal.get() 获取值进行操作
} finally {
threadLocal.remove(); // 避免内存泄漏
}
- 使用完
