这个问题取自Kathy Sierra SCJP 1.6。有多少对象符合垃圾回收条件?
根据凯西·塞拉的回答,这是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
- 乙: 1
- C: 2
- D:编译失败
- E:不可能知道
- F:运行时引发异常
答:
- C 是正确的。只有一个 CardBoard 对象 (c1( 符合条件,但它有一个关联的
Short
包装器对象也符合条件。 - 基于上述情况,A、B、D、E 和 F 不正确。(目标7.4(
让我们逐行分解:
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
变量本身不受影响。然后我们返回空参数。 c3
null
,c1
和c2
不受影响。我们仍然有 4 个对象,其中没有一个可以 GC'd。
c1 = null;
我们无效c1
.c1
之前指向的CardBoard
对象现在没有任何指向它的内容,它可以是GC'd。因为CardBoard
对象内部的story
变量是唯一指向Short
的东西,并且因为CardBoard
对象符合GC的条件,所以Short
也有资格获得GC。这给了我们 4 个对象,其中 2 个可以是 GC'd。符合 GC 条件的对象是以前由 c1
和 c1.story
引用的对象。
c3
指向的对象从未存在过。 构造函数只被调用了两次,两个对象,c1
和c2
分别指向一个对象。 c3
只是一个引用,除了空指针之外,从未分配过任何东西。
当前指向 null 的引用c3
不会超出范围并从堆栈中删除,直到 main 方法末尾的右大括号被交叉。
最初分配给c1
的对象无法访问,因为c1
引用设置为 null,但c2
引用尚未更改,因此仍可通过c2
引用从此范围访问分配给它的对象。
c3
是null
的,所以显然没有对象有资格进行垃圾回收。
请注意,仅创建两个CardBoard
对象,即以下行上的两个对象:
CardBoard c1 = new CardBoard();
CardBoard c2 = new CardBoard();
在参考杂耍之后,只有一个没有参考。
正式的正确答案是我们不知道。而我们不知道的原因是这句话:
Short story = 200;
这将编译为以下字节码:
CardBoard();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()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 超出了"必须缓存"范围,因此属于"可能缓存"。如果缓存了,则当包含story
实例时,CardBoard
的值将不符合 GC 的条件。如果未缓存,story
将无法访问,因此将进行 GC 处理。
为了使问题明确(并且建议的答案正确(,代码应像这样修改:
Short story = new Short(200);
更新:1.6 Javadoc for Short.valueOf()
比我引用的 1.8 版本更神秘,但同样的逻辑适用:无法仅通过查看代码来判断是否会返回Short
的新实例或缓存实例。
如果您注意到代码中只创建了两个对象。 C3 永远不会初始化为对象,它是一个空引用。因此,只有一个"对象"符合垃圾回收条件。