threadlocal内存泄露图解

threadlocal内存泄露图解_第1张图片

每个thread中都存在一个map, map的类型是ThreadLocal.ThreadLocalMap. Map中的key为一个ThreadLocal实例. 这个Map的确使用了弱引用,不过弱引用只是针对key. 每个key都弱引用指向ThreadLocal实例. 当把threadlocal ref 置为null以后,没有任何强引用指向ThreadLocal实例,所以ThreadLocal实例将会被gc回收. 但是,我们的value却不能回收,因为存在一条从current thread连接过来的强引用. 只有当前thread结束以后, current thread ref 就不会存在栈中,强引用断开, Current Thread, Map, value将全部被GC回收.
  所以得出一个结论就是只要这个线程对象被gc回收,就不会出现内存泄露,但在threadLocal设为null和线程结束这段时间不会被回收的,就发生了我们认为的内存泄露。其实这是一个对概念理解的不一致,也没什么好争论的。最要命的是线程对象不被回收的情况,这就发生了真正意义上的内存泄露。比如使用线程池的时候,线程结束是不会销毁的,会再次使用的。就可能出现内存泄露。

回归到内存泄露是因为WeakReference Key的问题,当然,Java的各位大佬肯定早就想到这个问题了,如果key==null的时候,就可以认为这个值无效了,可以调用expunged进行清理

而这个expungeStaleEntry方法在get、set时都会有间接的调用,而且remove方法中也会显示的调用,这也就是为什么有的文章中说通过在线程调用完成之后,通过调用remove方法能有效的杜绝该泄露问题的原因。

可能泄露的场景仅且仅在:
1.线程run方法结束后没有显示的调用remove进行清理
2.线程在线程池的模式下,一直重复运行

threadLocal.remove();

你可能感兴趣的:(threadlocal内存泄露图解)