SCJP 想知道对象何时被垃圾收集的问题?

Posted

技术标签:

【中文标题】SCJP 想知道对象何时被垃圾收集的问题?【英文标题】:SCJP Question to Figure When Object Gets Garbage Collected? 【发布时间】:2011-04-01 14:53:03 【问题描述】:

即使得到正确答案,我也无法弄清楚 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 行仍然有对它的引用?

【问题讨论】:

【参考方案1】:

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

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

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

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


这个问题还有另一个转折点......

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

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

【讨论】:

【参考方案2】:

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

【讨论】:

问题是关于myInt 引用的对象...而不是myInt 的引用。 (事实上​​,在 Java 中你不能引用变量。)【参考方案3】:

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

在我看来,myInt 引用的对象在函数doStuff 返回(第 8 行)之前将无法用于收集。 myInt 引用的对象存储在 arr 中,直到函数返回为止。

【讨论】:

“与流行的看法相反......”。并不真地。没有半点线索的人相信:-)【参考方案4】:

arrmyInt 最后在第 5 行引用。由于第 7 行没有引用它,我可以看到为什么第 6 行是规定的答案。

【讨论】:

【参考方案5】:

来自JLS §12.6.1:

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

因此,在此定义下,arr 引用的数组在第 6 行之后可以认为是不可访问的,因此其元素也不可访问。

【讨论】:

以上是关于SCJP 想知道对象何时被垃圾收集的问题?的主要内容,如果未能解决你的问题,请参考以下文章

对象何时有资格进行垃圾收集?

如果没有保存引用,SystemTimers.Timer 何时被视为垃圾?

C# 和 Java 中的垃圾收集

何时以及如何将 java 类加载器标记为垃圾收集?

java垃圾是怎么回收的,回收算法

Java Yourkit Profiler 显示 5K+ char[] 对象没有被垃圾收集,我怎么知道哪个类是罪魁祸首?