2

即使得到正确答案,我也无法弄清楚 SCJP 问题:

从以下代码(来源:http : //scjptest.com)中,我们需要确定被引用为 myInt 的对象何时有资格进行垃圾回收:

01.public void doStuff() {  
02.    Integer arr[] = new Integer[5];  
03.    for (int i = 0; i < arr.length; i++) {  
04.        Integer myInt = new Integer(i);  
05.        arr[i] = myInt;  
06.    }  
07.    System.out.println("end");  
08.}

答案表明它符合第 6 行的 GC 条件。但我认为该对象在第 7 行之后才符合 GC 条件。因为,被引用为 myInt 的对象也被称为 arr[i]。所以,你不觉得,因为在 myInt 超出范围之后, arr[] 直到第 8 行仍然引用它?

4

5 回答 5

5

arrSCJP 回答的原因是,在第 6 行,在引用它的范围内没有剩余的语句。在正常情况下,这将使数组及其元素有资格进行垃圾回收。

(Java 语言规范(12.6.1)这样说:

“可达对象是可以从任何活动线程在任何潜在的持续计算中访问的任何对象。可以设计优化程序的转换,以减少可达对象的数量,使其少于那些天真地认为可达的对象。例如,编译器或代码生成器可能会选择将不再使用的变量或参数设置为 null,以使此类对象的存储可能更快地被回收。”

如您所见,可达性的真正定义实际上并不基于范围。)


这个问题还有另一个转折……

如果他们已经分配imyInt,自动装箱将使用Integer.valueOf(i),并且该方法会将Integer对象记录在static缓存中。此缓存将导致对象保持可访问...

但是,Integer实例是使用 创建的new,因此不会发生缓存。并且该对象第 6 行无法访问。

于 2011-04-01T15:16:30.810 回答
3

arr[i] = myInt创建对 的引用的副本new Integer(i),而不是对 的引用myInt;因此, myInt 并不严格要求在该分配之后存在。

于 2011-04-01T14:57:57.047 回答
1

与流行的看法相反,Java 对象变量包含对对象的引用,而不是对象本身。当一个对象变量分配给另一个对象变量时,将复制引用而不是对象。AFAIK GC 用于对象而不是引用。我们都知道 GC 在不存在对它的引用时声明一个对象。

在我看来,在函数返回之前(第 8 行),引用的对象将myInt无法用于收集。doStuff被引用的对象myInt被存储在arr函数返回之前的范围内。

于 2011-04-01T15:08:19.933 回答
0

arr并且myInt最后在第 5 行引用。由于第 7 行没有引用它,我可以看到为什么第 6 行是所述的答案。

于 2011-04-01T15:17:14.383 回答
0

JLS §12.6.1

可达对象是可以从任何活动线程的任何潜在持续计算中访问的任何对象。可以设计优化程序的转换,将可到达的对象的数量减少到比那些天真地认为是可到达的要少。例如,编译器或代码生成器可能会选择将不再使用的变量或参数设置为 null,以使此类对象的存储空间可能更快地被回收。

所以,在这个定义下,第 6 行之后引用的数组arr可以被认为是不可达的,因此它的元素也是不可达的。

于 2011-04-01T15:32:36.410 回答