java中的各种引用
强引用
软引用–>内存不足时,JVM会尝试回收
弱引用–>不管内存是否足,JVM都有可能进行回收
如 weakHashMap. 它的key就是弱引用
key对象的强引用被置null时,此时仅剩弱引用。
即bookA = null 但是对象还在entrySet里面。
如果不想手动删除键值对。那么这种方式更高效。
JVM回收弱可达的booA. 同时弱引用对象会回到引用队列。
虚引用–> 幻影引用,幽灵引用
不影响声明周期,也无法根据虚引用获取对象
虚引用需要将 对象与一个队列绑定。
垃圾回收阶段虚引用收到一个通知。
在垃圾回收阶段,将虚引用入队。出队后再销毁。
用于跟踪垃圾回收。通过检查队列中有无虚引用,来确定是否已经被回收。
调用finalize之后,释放之前。这段时间对象是虚可达的。虚引用可以阻止对象被释放。可以显式或者隐式移除虚引用之后,就能被释放了。显示移除虚引用,可以手动从队列中移除这个虚引用,然后置null即可。很重要的用途,堆外内存释放。DirectByteBuffer.
ThreadLocal 为什么容易内存泄露,best practice是什么:
Thread类中的成员变量 ThreadLocalMap ,其中对于key(ThreadLocal)是弱引用。线程结束时,线程业务代码对key value的引用
best practice: 调用threadLocal.remove 间接的会找到当前线程的threadLocalMap,进行remove entry.
所以说根本原因是key能释放。但是map对entry的引用还在。导致有很多残留的value没法及时释放。get set remove时,ThreadLocalMap 会进行启发性清理临近无效key。但是最好不要依赖这种机制。而是在代码中的finnaly中显示的执行threadLocal.remove.
这种全局唯一的key就难以发生内存泄露。
另外一个场景是方法A内声明一个ThreadLocal
综上来看,如果一定要临时变量里使用Threadlocal。应该在方法的最顶层的第一行去建立。(适用于想传参下去的场景,但是又不想一个一个改入参)。另外要注意finally 进行remove防止内存泄露,尤其是线程池场景。
关键词线程池— entry对key 弱引用 threadLocal