为何“看不见”?对象没有立即收集?

发布于 2024-12-17 03:51:08 字数 865 浏览 3 评论 0原文

我刚刚读了这篇文章:垃圾收集的真相

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

在下面的代码中,分配给变量 foo 的对象在离开 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 可以简单地弹出所有四个元素并丢弃它们。

I just read this article: The Truth About Garbage Collection

In section "A.3.3 Invisible" it is explained how and when an object gets into the invisible state.

In the below code, the object assigned to the variable foo will become invisible after leaving the try/catch block and will remainly strongly referenced until the run method exits (which will never happen, because the while loop runs forever).

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

It is stated in this article:

However, an efficient implementation of the JVM is unlikely to zero
the reference when it goes out of scope.

Why is that not efficient?

My attempt at an explanation is as follows:

Say the stack for this method contains four elements, with the now invisible object being at the bottom.
If you want to collect the object instantly, you would have to pop and store three elements, pop and discard the fourth element and then push the three still valid elements back onto the stack.
If you collect the invisible object after control flow has left the run method, the VM could simply pop all four elements and discard them.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

债姬 2024-12-24 03:51:08

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

归零效率低下,因为不需要它:

  • 它不会导致立即垃圾收集周期,
  • 零可能很快就会被程序逻辑指定的另一个值覆盖。
  • 超出范围意味着局部变量不再是垃圾回收根集的一部分。因此,在超出范围之前它所持有的值(零或有效引用)并不重要;无论如何也不会被检查。

编辑:

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

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

The local variables are not on the operand stack, but in the local variables area in the activation frame, accessed, in the case of references via aload and astore bytecodes and zeroing a local variable does not involve any pushing and popping.

Zeroing is inefficient because it is not needed:

  • it would not cause an immediate garbage collection cycle
  • the zero may soon be overwritten by another value as dictated by the logic of the program.
  • going out of the scope means that the local variable is no longer part of the root set for garbage collection. As such what value it held immediately before going out of scope - zero or a valid reference - is immaterial; it won't be examined anyway.

EDIT:

Some comments on the last statement.

Indeed, at a bytecode level there are no scopes and a local variable slot may remain a part of the root set until the method returns. Of course, a JVM implementation can determine when a local variable slot is dead (i.e. all possible paths to method return either don't access the variable or are stores) and don't consider it a part of the root set, but it is by no means required to do so.

温折酒 2024-12-24 03:51:08

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

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

The very simple answer is b/c is inefficient.

There are many garbage collector algorithms and some may aggressively collect. Some compilers do allocation on the stack but the most obvious in your case is: doSomething() may actually keep (leak) a reference to the object elsewhere.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文