为何“看不见”?对象没有立即收集?
我刚刚读了这篇文章:垃圾收集的真相
在“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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
局部变量不在操作数堆栈上,而是在激活帧中的局部变量区域中,在通过
aload
和astore
字节码引用并将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
andastore
bytecodes and zeroing a local variable does not involve any pushing and popping.Zeroing is inefficient because it is not needed:
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.
非常简单的答案是 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.