符合垃圾收集条件的对象
这个问题来自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
指向。 构造函数只调用了两次,两个对象,每个对象由c1
和c2
指向。 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参数。 c3
为null
, c1
和c2
不受影响。 我们仍然有4个对象,其中没有一个可以GC。
c1 = null;
我们null c1
。 c1
之前指向的CardBoard
对象没有指向它,它可以是GC’d。 因为CardBoard
对象中的story
变量是指向Short
的唯一内容,并且因为该CardBoard
对象符合GC的条件,所以Short
也有资格获得GC。 这给了我们4个对象,其中2个可以是GC。 符合GC条件的对象是以前由c1
和c1.story
引用的c1.story
。
c3
为null
,因此显然没有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永远不会初始化为对象,它是一个空引用。 因此,只有一个“对象”符合垃圾收集条件。