符合垃圾收集条件的对象

这个问题来自Kathy Sierra SCJP 1.6 。 有多少个对象符合垃圾收集的条件?

根据Kathy Sierra的回答,这是C 这意味着两个对象有资格进行垃圾回收。 我给出了答案的解释。 但为什么c3不符合垃圾收集 (GC)的条件?

 class CardBoard { Short story = 200; CardBoard go(CardBoard cb) { cb = null; return cb; } public static void main(String[] args) { CardBoard c1 = new CardBoard(); CardBoard c2 = new CardBoard(); CardBoard c3 = c1.go(c2); c1 = null; // Do stuff } } 

何时达到了这些// Do stuff ,有多少对象符合GC条件?

  • 答:0
  • B:1
  • C:2
  • D:编译失败
  • E:不可能知道
  • F:运行时抛出exception

回答:

  • C是对的。 只有一个CardBoard对象(c1)符合条件,但它具有相关的Short包装器对象,该对象也符合条件。
  • 基于以上原因,A,B,D,E和F不正确。 (目标7.4)

没有任何对象存在c3指向。 构造函数只调用了两次,两个对象,每个对象由c1c2指向。 c3只是一个引用,除了空指针之外从未分配过任何东西。

当前指向null的引用c3将不会超出范围并从堆栈中删除,直到超过main方法结束时的右括号。

最初分配给c1的对象无法访问,因为c1引用设置为null,但c2引用尚未更改,因此分配给它的对象仍可通过c2引用从此作用域访问。

让我们逐行打破这个:

 CardBoard c1 = new CardBoard(); 

我们现在有两个对象, CardBoard c1指向和Short c1.story 。 对于GC而言,两者都不可用,因为CardBoard c1点和Short CardBoard点的story变量…

 CardBoard c2 = new CardBoard(); 

与上面类似,我们现在有四个对象,其中没有一个可用于GC。

 CardBoard c3 = c1.go(c2); 

我们调用c1指向的CardBoard上的方法,传递c2的值,它是对CardBoard对象的引用。 我们使参数为空,但Java是按值传递的,这意味着c2变量本身不受影响。 然后我们返回nullled参数。 c3nullc1c2不受影响。 我们仍然有4个对象,其中没有一个可以GC。

 c1 = null; 

我们null c1c1之前指向的CardBoard对象没有指向它,它可以是GC’d。 因为CardBoard对象中的story变量是指向Short的唯一内容,并且因为该CardBoard对象符合GC的条件,所以Short也有资格获得GC。 这给了我们4个对象,其中2个可以是GC。 符合GC条件的对象是以前由c1c1.story引用的c1.story

c3null ,因此显然没有Object符合垃圾回收的条件。

请注意,只创建了两个CardBoard对象,这两个对象在这些行上:

 CardBoard c1 = new CardBoard(); CardBoard c2 = new CardBoard(); 

在参考杂耍之后,其中只有一个没有参考。

正式的答案是我们不知道。 我们不知道的原因是这一行:

 Short story = 200; 

这将编译为以下字节代码:

 CardBoard(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: aload_0 5: sipush 200 8: invokestatic #2 // Method java/lang/Short.valueOf:(S)Ljava/lang/Short; 11: putfield #3 // Field story:Ljava/lang/Short; 14: return 

第8行是关键, Short.valueOf() ,它返回原始200的盒装等价物。 让我们看一下Short.valueOf()的Javadoc:

此方法将始终缓存-128到127(包括端点)范围内的值,并可以缓存此范围之外的其他值。

200超出“必须缓存”范围,因此它属于“可以缓存”。 如果缓存,则当包含CardBoard实例时, story的值不适用于GC。 如果没有缓存, story将无法访问,因此GCed。

为了使问题明确(并且建议的答案正确),代码应该像这样修改:

 Short story = new Short(200); 

更新:用于Short.valueOf()的1.6 Javadoc比我引用的1.8版本更加神秘,但同样的逻辑适用:没有办法通过查看代码来判断Short的新实例或缓存实例是否会被退回

如果您注意到代码中只创建了两个对象。 c3永远不会初始化为对象,它是一个空引用。 因此,只有一个“对象”符合垃圾收集条件。