为什么只有 1 个对象符合 GC 的条件?
Why is only 1 object eligible ready for GC?
当到达包含“//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.
虽然缺少指向对象的参考图是对象无法访问的明确且易于测试的证据,但存在此类参考并不一定意味着“潜在的持续计算”将实际访问它。这更难测试,但一个实现是否真的这样做并不影响对象是否正式“符合垃圾收集条件”*。
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? regarding this topic and finalize() called on strongly reachable objects in Java 8 关于垃圾收集的幼稚假设导致的现实生活问题。
不过,这些都是关于 可观察到的 行为。在问题的代码中,Alpha
和 Beta
都没有 finalize()
方法可以使它们的实例集合可观察,因此原则上,JVM 可以回收所有对象的内存,包括一个由 static
字段引用,没有人注意到。
* 一件事,这些问题很少说,他们是在谈论理论还是实践。形式上,符合垃圾回收条件的对象远多于实现可能实际识别的对象。识别未使用变量的能力可能取决于优化状态,而简短的 main
方法很少得到优化。另一方面,垃圾收集器通常不会运行执行这么短的时间,而是JVM会释放整个堆。
因此理论上,几乎所有对象都符合垃圾回收条件,而实际上,none 根本没有被回收。所以这两种观点都没有得出数字,提问者想听...
当到达包含“//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.
虽然缺少指向对象的参考图是对象无法访问的明确且易于测试的证据,但存在此类参考并不一定意味着“潜在的持续计算”将实际访问它。这更难测试,但一个实现是否真的这样做并不影响对象是否正式“符合垃圾收集条件”*。
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? regarding this topic and finalize() called on strongly reachable objects in Java 8 关于垃圾收集的幼稚假设导致的现实生活问题。
不过,这些都是关于 可观察到的 行为。在问题的代码中,Alpha
和 Beta
都没有 finalize()
方法可以使它们的实例集合可观察,因此原则上,JVM 可以回收所有对象的内存,包括一个由 static
字段引用,没有人注意到。
* 一件事,这些问题很少说,他们是在谈论理论还是实践。形式上,符合垃圾回收条件的对象远多于实现可能实际识别的对象。识别未使用变量的能力可能取决于优化状态,而简短的 main
方法很少得到优化。另一方面,垃圾收集器通常不会运行执行这么短的时间,而是JVM会释放整个堆。
因此理论上,几乎所有对象都符合垃圾回收条件,而实际上,none 根本没有被回收。所以这两种观点都没有得出数字,提问者想听...