Java WeakReference关联对象无强引用时get()未返回null问题
问题解答
你对WeakReference的基础规则认知没有错:当弱引用关联的对象不存在任何强引用指向、处于可回收状态时,GC执行后会清空对应弱引用,此时get()方法才会返回null。你看到的运行结果和预期不符,是两个认知偏差导致的:
- 错误认为方法返回、栈上局部变量失效后,对应的对象会立刻被回收
- 错误认为只要对象失去强引用,弱引用会立即自动清空,不需要GC参与
具体逻辑说明
1. 垃圾回收不是实时触发的
newPoint()方法返回时,栈上的局部变量referent确实会出栈失效,此时Point对象已经没有强引用链关联,进入了可回收候选状态。但JVM的GC机制是按需触发的,不会在方法返回的瞬间就启动回收流程:从newPoint()返回,到执行System.out.println(wp.get())的整个过程中,没有任何触发GC的条件,程序会直接执行打印逻辑,自然能拿到未被回收的对象引用。
2. 特殊场景下的隐式强引用
就算你在拿到wp后主动调用System.gc()提示JVM执行垃圾回收,在部分运行环境下也可能出现get()不为null的情况:
- 解释执行模式下,JVM不会主动清理局部变量表中已经出作用域的引用槽位,只要槽位没有被其他变量复用,JVM仍会判定对象存在强引用,不会回收
- 开启JIT逃逸分析优化时,如果对象没有逃逸出方法范围,可能会被直接分配在栈上而不是堆中,不会走常规的堆GC回收流程,弱引用的表现也会和预期有差异
复现预期结果的测试方式
你可以修改main方法,主动触发GC并预留回收执行时间,就能看到符合认知的结果:
public static void main( String[] args ) { App a = new App(); WeakReference<Point> wp = a.newPoint(); // 提示JVM执行垃圾回收 System.gc(); // 等待GC完成,避免主线程执行过快 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(wp.get()); // 常规运行环境下此处输出为null }
内容的提问来源于stack exchange,提问作者Troskyvs
相关产品推荐
相关产品推荐

