垃圾收集隐形变量

时间:2011-11-07 12:08:25

标签: java java-memory-model

我有以下代码:

void method() {
   Object o1 = new Object();
   {
      Object o2 = new Object();
      System.out.println(o2);
   }
   // any long operation
}

在执行long operation期间,o2对象是否有资格进行垃圾回收?

4 个答案:

答案 0 :(得分:2)

可达性的JLS定义是:

  

"可达对象是任何可能继续访问的对象   从任何实时线程计算。"

在这种情况下,在<{em>} println调用返回之前,正在进行的组合理论上无法访问该引用。 (我假设println(o2)没有在某处保存其引用。)


但是,在实践中,现有的JVM不能告诉对象在调用期间无法访问,并且大多数JVM只会在... {o2超出范围后才会注意到这一点。即使这样,GC运行也不能保证删除对象。


注意:这并不与JLS相矛盾,因为&#34;可达对象&#34;测试是真的告诉你什么时候赢得被垃圾收集,而不是什么时候收集。 JLS小心地指定一个对象可以最终确定并在它变得无法访问之后的某个时刻收集垃圾,但它也可能永远不会最终确定并进行垃圾收集。< / p>

答案 1 :(得分:0)

是的,但这取决于JVM / JIT是否不会对此进行优化以避免多余的堆栈操作

会使它成为

Object o1 = new Object();
Object o2 = new Object();
System.out.println(o2);
// any long operation

许多编译器会将所需的所有局部变量分组并找出所需的最大空间以保留所有这些变量(有些将被删除并保存在寄存器中)并相应地增加堆栈并且只在函数返回后将其缩小

这意味着o2将根据GC保留在“可访问”内存中,除非它被另一个范围中的另一个变量覆盖

答案 2 :(得分:0)

您需要了解变量o2和OBJECT DESIGNATED BY o2是不同的。

变量 o2实际上是一个指针(尽管Java更喜欢称它们为#34;引用&#34;)并占用自动堆栈帧中的4或8个字节。此存储不是垃圾回收,只有从程序返回时才会消失(或者根据编译器实现退出{}括号时可能会消失)。

对象&#34;由&#34;指定(指向)o2在new Object()操作结束后基本上可用于可能的垃圾收集,并且在o2中存在指向它的指针就是阻止这一点。一旦变量o2不再存在于堆栈帧中或者存储了不同的指针值,那么该对象就有资格被收集。

因此,在您的特定情况下,答案是&#34;也许&#34;。这取决于编译器和JIT如何处理{},以及一些&#34;运气&#34;问题是,在退出{}块(但不是整个方法)之后,o2的存储位置是否被重用于其他东西。

答案 3 :(得分:0)

没有。即使o2引用的对象不可访问,也不会进行垃圾回收。它处于可达和不可达之间的状态,称为“不可见”,因为引用变量o2仍在堆栈中。

要使对象可以收集垃圾,请指定o2 = null或将该块放在另一个函数中。

来源:A 2001 book on Java performance