
本教程通过分析一段典型java引用赋值代码,详解对象可达性与垃圾回收 eligibility 的判断逻辑,明确指出执行完三步引用重定向后,仅1个对象因完全不可达而符合gc条件。
本教程通过分析一段典型java引用赋值代码,详解对象可达性与垃圾回收 eligibility 的判断逻辑,明确指出执行完三步引用重定向后,仅1个对象因完全不可达而符合gc条件。
在Java内存管理中,一个对象是否“有资格被垃圾回收”(eligible for garbage collection),唯一判定标准是该对象是否还存在任何从GC Roots(如主线程栈帧中的局部变量)可达的强引用路径。只要没有任何强引用指向它,它就成为GC候选者——与对象是否“被命名”、是否“曾被引用过”或“是否内容重复”无关。
我们逐行分析题干代码:
public class Test {
public static void main(String[] args) {
Test s1 = new Test(); // 创建对象A,s1 → A
Test s2 = new Test(); // 创建对象B,s2 → B
Test s3 = new Test(); // 创建对象C,s3 → C
s1 = s3; // s1 现在 → C(A失去s1引用)
s3 = s2; // s3 现在 → B(C失去s3引用)
s1 = s2; // s1 现在 → B(C彻底失去所有引用!)
}
}为清晰追踪,我们用字母标记三个堆对象:
- 初始:s1 → A,s2 → B,s3 → C
- s1 = s3; → s1 → C,此时:s1→C, s2→B, s3→C(A仅剩0引用,但注意:此时尚未执行完全部语句)
- s3 = s2; → s3 → B,此时:s1→C, s2→B, s3→B(A仍无引用;C仅由s1指向)
- s1 = s2; → s1 → B,执行完毕后最终状态:
- s1 → B
- s2 → B
- s3 → B
✅ 对象B:被s1、s2、s3三个变量同时引用 → 可达,不可回收
❌ 对象A:自第4行s1 = s3起再无任何引用指向它 → 自始不可达,全程 eligible
❌ 对象C:在第5行s3 = s2后,仅s1指向它;但在第6行s1 = s2后,s1也不再指向C → 此时C也完全失去所有强引用 → 自第6行执行完毕起 eligible
⚠️ 关键纠正:题干答案解析中称“s3='C'”是错误的——第5行 s3 = s2 已使 s3 指向 B;第6行 s1 = s2 并未改变 s3,因此最终 s3 → B,而非 C。原答案混淆了中间状态与最终状态。
立即学习“Java免费学习笔记(深入)”;
因此,执行完第6行(即题干所指“line 11: s1 = s2”之后):
- 对象A:自第4行起已不可达
- 对象C:自第6行起不可达
- 对象B:始终被至少一个变量(s2)引用
→ 共 2个对象(A 和 C)满足垃圾回收条件。
✅ 正确答案是:B. After line 11, two objects are eligible for garbage collection.
? 补充说明:
- Java GC 不关心对象内容是否“相同”或“冗余”,只认引用图的连通性;
- 局部变量作用域在 main 方法结束时才释放,但只要变量仍处于作用域内且持有引用,其所指对象就不可回收;
- 本例中所有对象均为局部变量引用,无静态字段、线程栈外引用或JNI引用等复杂情况,分析可聚焦于栈变量指向关系。
总结:判断GC eligibility,务必画出每一步引用变更后的最终可达性快照,而非依赖直觉或中间状态。严谨追踪引用流向,是掌握JVM内存模型的关键第一步。


















