为什么没有立即收集“隐形”物体?

时间:2011-11-19 16:26:51

标签: java garbage-collection object-lifetime

我刚读过这篇文章:The Truth About Garbage Collection

“A.3.3 Invisible”部分中,解释了对象如何以及何时进入invisible状态。

在下面的代码中,分配给变量foo的对象在离开invisible块后将变为try/catch,并且在run方法退出之前将一直强烈引用(这将永远不会发生,因为while循环永远运行。

public void run() {
    try {
        Object foo = new Object();
        foo.doSomething();
    } catch (Exception e) {
        // whatever
    }
    while (true) { // do stuff } // loop forever
}

本文说明:

  

但是,JVM的有效实现不可能为零   超出范围时的参考。

为什么效率不高?

我尝试解释如下:

假设此方法的堆栈包含四个元素,现在不可见的对象位于底部 如果你想立即收集对象,你必须弹出并存储三个元素,弹出并丢弃第四个元素,然后将三个仍然有效的元素推回堆栈。
如果在控制流离开run方法后收集不可见对象,则VM可以简单地弹出所有四个元素并丢弃它们。

2 个答案:

答案 0 :(得分:3)

局部变量不在操作数堆栈上,而是在激活帧的局部变量区域中,在通过aloadastore字节码引用并将局部变量归零的情况下访问不涉及任何推动和弹出。

归零是低效的,因为它不需要:

  • 它不会导致立即的垃圾收集周期
  • 零可能很快被另一个值覆盖,如程序逻辑所指示的那样。
  • 超出范围意味着局部变量不再是垃圾收集根集的一部分。因此,在超出范围之前立即保留的价值 - 零或有效参考 - 是无关紧要的;无论如何都不会被检查。

修改

对最后一项声明的一些评论。

实际上,在字节码级别没有作用域,并且局部变量槽可以保留为根集的一部分,直到该方法返回。当然,JVM实现可以确定局部变量槽何时死亡(即方法返回的所有可能路径都不访问变量或存储)并且不认为它是根集的一部分,但它是绝不需要这样做。

答案 1 :(得分:0)

非常简单的答案是b / c效率低下。

有许多垃圾收集器算法,有些可能会积极收集。有些编译器会在堆栈上进行分配,但在您的情况下最明显的是:doSomething()实际上可能会在其他地方保留(泄漏)对象的引用。