public class Test {
public static void main(String[] args) throws Exception {
A aObject = new A();
ReferenceQueue<A> queue = new ReferenceQueue<>();
PhantomReference<A> weak = new PhantomReference<>(aObject, queue);
aObject = null;
System.gc();
TimeUnit.SECONDS.sleep(1);
System.out.println(queue.poll());
}
}
class A{
@Override
protected void finalize() throws Throwable {
// TODO Auto-generated method stub
super.finalize();
System.out.println("finalize");
}
}
The result is:
finalize
null
but if i delete the finalize method in class A, the result is:
java.lang.ref.PhantomReference@5b2c9e5d
so, the result shows that when I override the finalize method, the weak object isn't put into the reference queue, is that because the aObject resurrected? But I don't do anything in the finalize method
With a nontrivial finalize
, Java knows the object is unreachable* before finalize
runs, but it doesn't know the object is still unreachable after finalize
.
It has to wait for the object to be deemed unreachable again in another GC cycle before it can enqueue the phantom reference.
*not quite unreachable in the terminology of the java.lang.ref docs, but neither strongly, softly, nor weakly reachable
Very interesting observation. Here is what is happening:
When class has non-trivial (non empty in OP case) finalize
method the JVM will create a java.lang.ref.Finalizer
(which is a subclass of Reference
) object and point it to our referent, in this case A object. This in turn will prevent PhantomReference
to enqueue it since A is already referenced by Finalizer
.
This was observer by me in debugger using Java 1.8 and also described in detail here.
The observation from @Turing85 is expected since when we remove all statements inside finalize
method it becomes trivial and behaves just like any class without finalize
method and wont be referenced by Finalizer
.
Update:
The question was asked if Finalizer
will clear its reference to A at all. The JVM does clear it on the subsequent GC runs, which in turn finally allows PhantomReference
to enqueue A into its reference queue.
For example running the below code with non-trivial finalize
method will get non null PhantomReference
from its reference queue.
public static void main(String[] args) throws Exception {
A aObject = new A();
ReferenceQueue<A> queue = new ReferenceQueue<>();
PhantomReference<A> pr = new PhantomReference<>(aObject, queue);
aObject = null;
System.gc();
TimeUnit.SECONDS.sleep(1);
System.gc();
TimeUnit.SECONDS.sleep(1);
System.out.println( queue.poll() );
}
Prints:
finalize
java.lang.ref.PhantomReference@15db9742
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With