Can Java finalize an object when it is still in scope?
Yes.
However, I'm being pedantic here. Scope is a language concept that determines the validity of names. Whether an object can be garbage collected (and therefore finalized) depends on whether it is reachable.
The answer from ajb almost had it (+1) by citing a significant passage from the JLS. However I don't think it's directly applicable to the situation. JLS §12.6.1 also says:
A reachable object is any object that can be accessed in any potential continuing computation from any live thread.
Now consider this applied to the following code:
class A {
@Override protected void finalize() {
System.out.println(this + " was finalized!");
}
public static void main(String[] args) {
A a = new A();
System.out.println("Created " + a);
for (int i = 0; i < 1_000_000_000; i++) {
if (i % 1_000_000 == 0)
System.gc();
}
// System.out.println(a + " was still alive.");
}
}
On JDK 8 GA, this will finalize a
every single time. If you uncomment the println
at the end, a
will never be finalized.
With the println
commented out, one can see how the reachability rule applies. When the code reaches the loop, there is no possible way that the thread can have any access to a
. Thus it is unreachable and is therefore subject to finalization and garbage collection.
Note that the name a
is still in scope because one can use a
anywhere within the enclosing block -- in this case the main
method body -- from its declaration to the end of the block. The exact scope rules are covered in JLS §6.3. But really, as you can see, scope has nothing to do with reachability or garbage collection.
To prevent the object from being garbage collected, you can store a reference to it in a static field, or if you don't want to do that, you can keep it reachable by using it later on in the same method after the time-consuming loop. It should be sufficient to call an innocuous method like toString
on it.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…