我有以下代码:
void method() {
Object o1 = new Object();
{
Object o2 = new Object();
System.out.println(o2);
}
// any long operation
}
o2 对象在执行期间是否有资格进行垃圾收集long operation
?
我有以下代码:
void method() {
Object o1 = new Object();
{
Object o2 = new Object();
System.out.println(o2);
}
// any long operation
}
o2 对象在执行期间是否有资格进行垃圾收集long operation
?
JLS 对可达性的定义是:
“可达对象是可以从任何活动线程的任何潜在持续计算中访问的任何对象。”
在这种情况下,在调用返回之前,该引用在理论上不再可供正在进行的计算访问。println
(我假设它println(o2)
不会将其引用保存在某处。)
然而,在实践中,没有 JVM 可以告诉对象在调用期间变得不可访问,并且大多数 JVM 只会在……或之后……o2
超出范围时才注意到这一点。即使这样,GC 运行也不能保证删除对象。
注意:这与 JLS 并不矛盾,因为“可达对象”测试实际上是在告诉您对象什么时候不会被垃圾回收,而不是什么时候会。JLS 小心地指定一个对象可能会在它变得无法访问后的某个时间点被终结和垃圾收集,但它也可能永远不会被终结和垃圾收集。
不会。即使 o2 引用的对象不可访问,它也不会被垃圾回收。它处于可访问和不可访问之间的状态,称为“不可见”,因为引用变量 o2 仍在堆栈上。
要使对象可被垃圾回收,请将该o2 = null
块分配或放入另一个函数中。
是的,但是这将取决于 JVM/JIT 是否不会对此进行优化以避免多余的堆栈操作
这会让它
Object o1 = new Object();
Object o2 = new Object();
System.out.println(o2);
// any long operation
许多编译器会将所有需要的局部变量分组,并计算出保留它们所需的最大空间(有些将被消除并仅保存在寄存器中)并相应地增加堆栈,并且仅在函数可以返回后收缩它
这意味着 o2 将根据 GC 保留在“可访问”内存中,除非它被另一个范围内的另一个变量覆盖
您需要了解您的变量o2
和 OBJECT DESIGNATED BYo2
是不同的。
变量o2 实际上是一个指针(尽管 Java 更喜欢称它们为“引用”)并且在自动堆栈帧中占据 4 或 8 个字节。此存储不会被垃圾收集,并且仅在您从过程返回时(或者可能在您退出{}
括号时,具体取决于编译器实现)时才会消失。
一旦new Object()
操作结束,o2 的“指定者”(指向者)对象本质上就可用于可能的垃圾回收,而 o2 中指向它的指针的存在就是阻止这种情况发生的全部因素。一旦变量 o2 不再存在于堆栈帧中或其中存储了不同的指针值,则该对象有资格被收集。
因此,在您的特定情况下,答案是“也许”。这取决于编译器和 JIT 如何处理{}
,以及一些“运气”问题,即在退出{}
块(但不是整个方法)后,o2 的存储位置是否被重用于其他东西。