即使得到了正确的答案,我也无法弄清楚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] as好。那么,你不觉得,因为,在myInt超出范围之后,arr []仍然会引用它直到第8行?
答案 0 :(得分:5)
SCJP答案的原因是,在第6行,arr
范围内没有剩余的陈述引用它。在正常情况下,这会使数组及其元素符合垃圾回收的条件。
(Java语言规范(12.6.1)说:
“可访问对象是任何可以从任何活动线程继续计算中访问的对象。可以设计优化程序转换,以减少可达到的对象数量小于天真地被认为是可达的。例如,编译器或代码生成器可以选择设置一个不再用于null的变量或参数,以使这种对象的存储可能更快地回收。“ < / p>
正如您所看到的,可达性的真正定义实际上并不基于范围界定。)
这个问题还有另一个转折点......
如果他们已将i
分配给myInt
,则自动装箱将使用Integer.valueOf(i)
,并且该方法会在Integer
缓存中记录static
个对象。此缓存会导致对象保持可访问状态......
但是,Integer
实例是使用new
创建的,因此不会发生缓存。并且第6行的 对象无法访问。
答案 1 :(得分:3)
arr[i] = myInt
创建对new Integer(i)
的引用的副本,而不是对myInt
的引用;因此,在该任务之后,并不严格要求myInt存在。
答案 2 :(得分:1)
与流行的看法相反,Java对象变量包含对对象的引用,而不包含对象本身。将一个对象变量分配给另一个对象变量时,将复制该引用而不是该对象。 AFAIK GC用于对象而非参考。我们都知道当没有引用它时,GC会声明一个对象。
在我看来,myInt
引用的对象在函数doStuff
返回(第8行)之前不可用于收集。 myInt
引用的对象存储在范围内的arr
中,直到函数返回。
答案 3 :(得分:0)
arr
和myInt
最后在第5行引用。由于第7行没有引用,我可以看到为什么第6行是陈述的答案。
答案 4 :(得分:0)
来自JLS §12.6.1:
可到达对象是可以从任何活动线程的任何潜在持续计算中访问的任何对象。可以设计优化程序的转换,以减少可达到的对象的数量,使其少于可以被认为可达的对象的数量。例如,编译器或代码生成器可以选择设置将不再用于null的变量或参数,以使得此类对象的存储可能更快地被回收。
因此,在这个定义下,arr
引用的数组在第6行之后可以被认为是不可达的,因此它的元素也是不可达的。