SoftReference自身何时被GC回收?GC如何处理引用对象已回收的SoftReference?
Java SoftReference 垃圾回收相关问题解答
首先先明确一个核心认知:SoftReference实例本身和它内部引用的目标对象(下称referent)是两个完全独立的堆对象,二者生命周期没有强制绑定关系,不要混为一谈。
SoftReference对象自身的GC回收时机
SoftReference本身没有任何回收特权,它的回收规则和普通Java对象完全一致:
- 只要存在从GC Roots出发的强引用链能抵达这个
SoftReference实例,它就绝对不会被回收,哪怕它内部持有的referent已经被GC清理、调用get()已经返回null。最常见的场景就是你把SoftReference实例作为value存到了缓存Map里,只要Map本身是存活的,这些SoftReference对象就会一直留在堆里。 - 当不存在任何强/软/弱引用链指向这个
SoftReference实例时,它会和其他普通不可达对象一样,在对应分代的GC触发时被正常回收,和它内部的referent是否存活没有关系。
常见误区:很多人以为referent被回收后
SoftReference对象自己也会立刻被回收,这是完全错误的。举个最简单的例子:方法局部变量持有的SoftReference,哪怕内部referent因为内存不足被清掉了,只要方法没执行完、局部变量还没出作用域,这个SoftReference对象就一直是强可达的,不会被回收。
referent被回收后GC对SoftReference对象的处理
当GC判定某个SoftReference的referent达到软引用回收阈值(即下次GC后仍然没有足够内存分配、即将抛出OutOfMemoryError前,会回收所有软可达的referent),会对对应的SoftReference对象做如下处理:
- 首先会原子性地把
SoftReference内部存储referent的字段置为null,这之后调用get()方法就会返回null,和原referent对象的引用关联被彻底切断。 - 后续处理取决于创建
SoftReference时是否关联了ReferenceQueue:- 如果关联了注册的引用队列:JVM内置的
ReferenceHandler后台线程会在GC完成后,把这个已经清空referent的SoftReference实例加入到对应的队列中。应用层可以轮询这个队列,拿到失效的SoftReference实例做后续清理,比如把它从自定义的缓存Map中移除,避免无效对象堆积。 - 如果没有关联任何引用队列:GC做完referent置空的操作后就不会有额外处理,这个
SoftReference对象会一直留在堆里,直到它自身不可达后被正常回收。
- 如果关联了注册的引用队列:JVM内置的
实践提示:如果用
SoftReference做内存敏感缓存,一定要关联ReferenceQueue并及时清理队列里失效的SoftReference实例,否则大量持有null referent的SoftReference对象会被缓存Map强引用一直占用内存,造成意料之外的内存泄漏。
内容的提问来源于stack exchange,提问作者MD.Luffy
相关产品推荐
相关产品推荐

