当到达包含“//doStuff”的行时,有多少对象可用于垃圾回收?
a. 0
b. 1
c. 2
d. 3
e. 4
f. 5
class Beta
{
}
class Alpha
{
static Beta b1;
Beta b2;
}
public class Tester
{
public static void main(String[] args)
{
Alpha a1=new Alpha();
Alpha a2=new Alpha();
Beta b1= new Beta();
Beta b2= new Beta();
a1.b1=b1;
a1.b2=b1;
a2.b2=b2;
a1=null;
b1=null;
b2=null;
//doStuff
}
}
给出的答案:1
我认为答案应该是 2,因为分配给 a1 和 b1 的对象不再可访问。
最佳答案
像这样的问题很少有任何意义。通常,提问者(面试官)在问题中加入了特定的陷阱,并且会认为任何识别陷阱的答案都是正确的,而忽略了问题的其他内在缺陷。
这里的问题是,赋值 a1.b1=b1;
分配给 static
字段,即使 a1
被分配给 null
。
问题“有多少对象可用于垃圾回收?”的根本缺陷是我们甚至不知道有多少物体存在。当进入 main
方法时,JVM 初始化和启动程序启动代码可能创建了任意数量的符合垃圾回收条件的临时对象,并且在到达指定点时仍然符合垃圾回收条件。
即使我们将问题限制为问题代码中可见的工件,给定的答案也是错误的。
The Java® Language Specification状态:
A reachable object is any object that can be accessed in any potential continuing computation from any live thread.
虽然缺乏指向对象的引用图可以清楚且易于测试地证明对象不可访问,但存在此类引用并不一定意味着“潜在的持续计算”实际上会访问它。这很难测试,但实现是否真正做到这一点并不影响该对象是否正式“有资格进行垃圾回收”*。
规范even makes clear :
Optimizing transformations of a program can be designed that reduce the number of objects that are reachable to be less than those which would naively be considered reachable. For example, a Java compiler or code generator may choose to set a variable or parameter that will no longer be used to
null
to cause the storage for such an object to be potentially reclaimable sooner.
我们有一个未使用的参数,args
,这里指向一个字符串数组,可以进行垃圾回收。事实上,在这个例子中,数组可能指向任意数量的符合垃圾回收条件的字符串,这再次得出可回收对象数量未知的结论。
这同样适用于局部变量a2
。只要随后不使用它,就不会阻止引用对象(以及 a2.b2
引用的 Beta
实例)进行垃圾回收。
另请参阅Can java finalize an object when it is still in scope?关于此主题和 finalize() called on strongly reachable objects in Java 8关于垃圾收集的天真假设所引起的现实生活问题。
不过,这些都是关于可观察的行为。在问题的代码中,Alpha
和 Beta
都没有 finalize()
方法来使其实例的集合可观察,因此原则上, JVM 可以在没有人注意到的情况下回收所有对象的内存,包括由 static
字段引用的对象。
* 这些问题很少提及的一件事是它们是在谈论理论还是实践。从形式上来说,符合垃圾回收条件的对象远多于实现实际识别的对象。识别未使用变量的能力可能取决于优化状态,并且简短的 main
方法很少得到优化。另一方面,垃圾收集器通常不会运行这么短的执行时间,而是 JVM 会整体释放整个堆。
因此,从理论上讲,几乎所有对象都有资格进行垃圾回收,但实际上,根本没有任何对象被回收。因此,两种观点都无法得出数字,提问者想听……
关于java - 为什么只有 1 个对象适合 GC?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57646371/