ThreadLocalMap的enrty的key为什么要设置成弱引用
ThreadLocalMap存储的格式是Entry<ThreadLocal, T>。
java中而引用传递的是对象的副本,如果使用强引用,当原来key原来对象失效的时候,jvm不会回收map里面的ThreadLocal。
弱引用 WeakReference定义:
如果一个对象只具有弱引用,那么垃圾回收器在扫描到该对象时,无论内存充足与否,都会回收该对象的内存。
hreadLocal是用空间换时间(牺牲空间)。因为synchronized操作数据,只需要在主存存一个变量即可,就阻塞等共享变量,而ThreadLocal是每个线程都创建一块小的堆工作内存。
一个线程对应一块工作内存,线程可以存储多个ThreadLocal。那么假设,开启1万个线程,每个线程创建1万个ThreadLocal,也就是每个线程维护1万个ThreadLocal小内存空间,而且当线程执行结束以后,假设这些ThreadLocal里的Entry还不会被回收,那么将很容易导致堆内存溢出。
ThreadLocalMap使用ThreadLocal的弱引用作为key,如果一个ThreadLocal没有外部强引用引用他,那么系统gc的时候,这个ThreadLocal势必会被回收,这样一来,ThreadLocalMap中就会出现key为null的Entry,就没有办法访问这些key为null的Entry的value,如果当前线程再迟迟不结束的话,这些key为null的Entry的value就会一直存在一条强引用链:
Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value
永远无法回收,造成内存泄露。
虽然,JDK调用ThreadLocalMap的getEntry函数或者set函数,会清除这些null key的entry,但是还不够。因为可能后面不调用这些函数了,所以这种方式不可能任何情况都能解决。
因此,很多情况下需要使用者手动调用ThreadLocal的remove函数,手动删除不再需要的ThreadLocal,防止内存泄露。所以JDK建议将ThreadLocal变量定义成private static的,这样的话ThreadLocal的生命周期就更长,由于一直存在ThreadLocal的强引用,所以ThreadLocal也就不会被回收,也就能保证任何时候都能根据ThreadLocal的弱引用访问到Entry的value值,然后remove它,防止内存泄露。
如果线程迟迟无法结束,也就是ThreadLocal对象将一直不会回收,例如线程池的情况,那么也将导致内存泄漏。(内存泄露的重点)
上一篇: python版本切换
下一篇: JAVA 内存泄露详解-值得收藏的好文