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