Java对象垃圾回收

4

我正在学习OCA Java认证考试,对于一个问题的答案不太确定应该如何理解。

public class Test {

public static void main(String[] args){
    Student s1 = new Student("o1"); 
    Student s2 = new Student("o2");
    Student s3 = new Student("o3");
    s1=s3; 
    s3=s2;
    s2=null;
    //HERE
    }
}

问题是在 //HERE 点之后哪个对象将可供垃圾回收。
在线测试提供的答案是:一个对象 (o1)。
有人可以解释一下为什么吗?

你应该阅读Jeanne Boyarsky和Scott Selikoff所著的《OCA:Oracle认证Java SE 8程序员I学习指南:考试1Z0-808》这本书。 - Ashish Mishra
4个回答

7
考虑一个简单的学生类。
第一步:
Student s1 = new Student("s1"); 
Student s2 = new Student("s2");
Student s3 = new Student("s3");

s1,s2,s3 引用堆空间中的三个对象。

enter image description here

步骤 2:

Student s1 = s3; 
现在引用了堆空间中的对象 堆空间中的对象已经失去了引用

enter image description here

第三步:

Student s1 = s3;
Student s3 = s2;

变量s1引用了s3堆空间

变量s3引用了s2堆空间

enter image description here

步骤4:
Student s1 = s3;
Student s3 = s2;
Student s2 = null;

变量s1引用了s3的堆空间

变量s3引用了s2的堆空间

变量s2失去了它的引用(空指针)

enter image description here

结论:

在第11行之后,一个对象符合垃圾回收的条件


我只是想知道如果有一个字符串,比如说String interest = "Q&A on Stackoverflow",然后我稍后将interest = null,那么它会被垃圾回收吗?因为我们知道String是Java中的不可变类,并且字符串存储在堆上的字符串池中,即使程序执行后仍然保留,这就是为什么我们避免将密码存储在String非原始类型中,因为它们可能存在于内存中,稍后可以使用内存转储进行黑客攻击,请给我指点! - Ashish Mishra
你引用了“第11行”,请问在问题或者你的回答中确切的位置是什么?如果你指的是在注释HERE之后,那么你的回答是非常不正确的。在那一行之后的所有内容都可以被垃圾回收。 - Eugene
@a1a1a1a1a1 请阅读问题下面的评论,并理解回答考试问题和现实之间的差异。那些垃圾收集器考试问题最多只能算不准确。 - Eugene
2
除了对“第11行”的混淆引用之外,使用双头箭头是错误的。对象没有对局部变量的反向引用。 - Holger

4
每次出现这种问题时,答案仍然是相同的:在注释HERE之后,每个对象都有资格进行垃圾回收。在那一行之后没有任何使用,因此不存在对任何对象的强引用,因此所有内容都可以进行GC。不幸的是,这种类型的问题只有在考试中获得正确“分数”的背景下才有意义,因此人们会按照它们的方式学习。实际情况是,在没有更广泛的可达性上下文的情况下,它们只会混淆用户的理解。
想一想 - 在那个注释之后你的对象是否有任何活动引用?没有。因此,每个实例是否都有资格进行GC?是的。并且请注意,它们是在那个注释之后有资格进行GC,而不是在方法结束之后。不要将作用域可达性混为一谈。

谢谢你的回答。 我理解你的观点。然而,在考试的背景下,我认为Boris提供的答案更符合预期的答案。 我同意这是一个奇怪的问题,我没有预料到这个考试在措辞上会如此欺骗人。 - a1a1a1a1a1
2
考试预期答案错误的事实凸显了这类问题更大的逻辑错误:“Java(以及其他现代编程语言)实现了垃圾回收,因此开发人员不需要处理它,即使专家有时也会犯错——所以让初学者扮演垃圾收集器,并以一种他们终身都不必再次处理内存管理的方式来处理它。” - Holger

1
Student s1 = new Student("o1"); 
Student s2 = new Student("o2");
Student s3 = new Student("o3");
s1=s3; // The "s1" variable now points to the object referenced to by s3, ie "o3"
s3=s2; // The "s3" variable now points to the object referenced to by s2, ie "o2"
s2=null; // The "s2" variable points to nothing

在执行结束时,“o3”和“o2”对象被变量(分别为“s1”和“s3”)引用。因此,“o1”对象不被任何变量指向,可以由垃圾回收器销毁。

1

退出方法后,所有对象都将有资格进行垃圾回收,因为s1、s2、s3是局部变量且引用未传递到外部。

然而,在方法的最后一行,s1持有对o3的引用,s2指向无处,s3指向o2。只有o1没有引用指向它,因此它有资格进行垃圾回收。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接