JVM 是否会收集不再使用的局部变量引用的对象?
据我所知,方法的局部变量位于执行线程的堆栈帧中,局部变量的引用类型只有对象的引用,而不是对象本身.JVM 中的所有对象都位于堆空间中.
As far as I know, a method's local variable is located in a stack frame in an executing thread and a reference type of a local variable only has a objects' reference, not the object itself. All of objects in JVM are located in a heap space.
我想知道正在执行的方法中由局部变量引用的对象在方法执行结束之前永远不会被垃圾收集.(不使用 java.lang.ref.WeakReference 和 SoftReference.)
I want to know that objects referenced by local variables in a method being executed are never garbage collected until the end of the method execution. (without using java.lang.ref.WeakReference and SoftReference.)
它们是垃圾收集的吗?还是从不?有编译器对这类东西的优化吗?
Are they garbage collected? or never? Is there compiler's optimization to this type of stuff?
(如果它们从不被垃圾回收,这意味着在执行需要很长时间的大方法时,可能需要将 null 分配给不再使用的变量.)
(If they are never garbage collected, this means it may be needed to assign null to variables no longer used when executing big methods which take long time.)
推荐答案
如Java能在对象还在的时候终结它吗scope?,局部变量不会阻止引用对象的垃圾收集.或者,正如this answer所说,范围只是一个语言概念,与垃圾收集器无关.
As elaborated in Can java finalize an object when it is still in scope?, local variables do not prevent the garbage collection of referenced objects. Or, as this answer puts it, scope is a only a language concept, irrelevant to the garbage collector.
我将引用规范的相关部分,JLS §12.6.1 再次:
I’ll cite the relevant part of the specification, JLS §12.6.1 again:
可达对象是可以在任何潜在的持续计算中从任何活动线程访问的任何对象.
A reachable object is any object that can be accessed in any potential continuing computation from any live thread.
此外,我将答案的示例扩展到
Further, I extended the answer’s example to
class A {
static volatile boolean finalized;
Object b = new Object() {
@Override protected void finalize() {
System.out.println(this + " was finalized!");
finalized = true;
}
@Override public String toString() {
return "B@"+Integer.toHexString(hashCode());
}
};
@Override protected void finalize() {
System.out.println(this + " was finalized!");
}
@Override public String toString() {
return super.toString() + " with "+b;
}
public static void main(String[] args) {
A a = new A();
System.out.println("Created " + a);
for(int i = 0; !finalized; i++) {
if (i % 1_000_000 == 0)
System.gc();
}
System.out.println("finalized");
}
}
Created A@59a6e353 with B@6aaa5eb0
B@6aaa5eb0 was finalized!
finalized
A@59a6e353 with B@6aaa5eb0 was finalized!
这表明即使是变量在范围内的方法也可以检测到引用对象的终结.此外,从堆变量中引用也不一定会阻止垃圾收集,因为 B
对象是不可访问的,因为当包含引用的对象也不可访问时,没有继续计算可以访问它.
which demonstrates that even the method with the variable in scope may detect the finalization of the referenced object. Further, being referenced from a heap variable doesn’t necessarily prevent the garbage collection either, as the B
object is unreachable, as no continuing computation can access it when the object containing the reference is unreachable too.
值得强调的是,即使使用对象并不总是会阻止其垃圾回收.重要的是,正在进行的操作是否需要对象的内存,而不是每次对源代码中对象字段的访问都必须在运行时导致实际的内存访问.规范规定:
It’s worth emphasizing that even using the object does not always prevent its garbage collection. What matters, is whether the object’s memory is needed for the ongoing operation(s) and not every access to an object’s field in source code has to lead to an actual memory access at runtime. The specification states:
可以设计优化程序的转换,将可到达的对象的数量减少到比那些天真地认为是可到达的要少.[…]
Optimizing transformations of a program can be designed that reduce the number of objects that are reachable to be less than those which would naively be considered reachable. […]
如果对象字段中的值存储在寄存器中,则会出现另一个例子.然后程序可能会访问寄存器而不是对象,并且永远不会再次访问对象.这意味着该对象是垃圾.
Another example of this occurs if the values in an object's fields are stored in registers. The program may then access the registers instead of the object, and never access the object again. This would imply that the object is garbage.
这不仅仅是一个理论上的选择.正如 finalize() 在 Java 8 中调用强可达对象 中所讨论的,它甚至可能在调用方法时发生在对象上在它们上,或者换句话说,this
引用可能会在实例方法仍在执行时被垃圾收集.
This is not only a theoretical option. As discussed in finalize() called on strongly reachable object in Java 8, it may even happen to objects while a method is invoked on them, or in other words, the this
reference may get garbage collected while an instance method is still executing.
确定防止对象垃圾回收的唯一方法是,如果终结器也对对象进行同步,则对对象进行同步或调用 Reference.reachabilityFence(object)
,Java 9 中添加的一种方法.fence 方法的后期添加展示了优化器在版本之间变得更好对早于预期的垃圾收集问题的影响.当然,首选的解决方案是编写完全不依赖垃圾回收时间的代码.
The only ways to prevent an objects garbage collection for sure, are synchronization on the object if the finalizer also does synchronization on the object or calling Reference.reachabilityFence(object)
, a method added in Java 9. The late addition of the fence method demonstrates the impact of the optimizers getting better from version to version on the issue of earlier-than-wanted garbage collection. Of course, the preferred solution is to write code that does not depend on the time of garbage collection at all.
相关文章