Searched a lot about phantom reference but unable to find its practical usage. And logically the get() method returns null in case of Phantom References
A weak reference allows the garbage collector to collect an object while still allowing an application to access the object. If you need the object, you can still obtain a strong reference to it and prevent it from being collected.
Unlike soft and weak references, phantom references are not automatically cleared by the garbage collector as they are enqueued. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable.
A weak reference permits the garbage collector to collect the object while still allowing the application to access the object. A weak reference is valid only during the indeterminate amount of time until the object is collected when no strong references exist.
A Soft reference is eligible for collection by garbage collector, but probably won't be collected until its memory is needed. i.e. garbage collects before OutOfMemoryError . A Weak reference is a reference that does not protect a referenced object from collection by GC.
You can follow this blog:
What good are PhantomReferences? I'm only aware of two serious cases for them: first, they allow you to determine exactly when an object was removed from memory. They are in fact the only way to determine that. This isn't generally that useful, but might come in handy in certain very specific circumstances like manipulating large images: if you know for sure that an image should be garbage collected, you can wait until it actually is before attempting to load the next image, and therefore make the dreaded OutOfMemoryError less likely.
Second, PhantomReferences avoid a fundamental problem with finalization: finalize() methods can "resurrect" objects by creating new strong references to them. So what, you say? Well, the problem is that an object which overrides finalize() must now be determined to be garbage in at least two separate garbage collection cycles in order to be collected. When the first cycle determines that it is garbage, it becomes eligible for finalization. Because of the (slim, but unfortunately real) possibility that the object was "resurrected" during finalization, the garbage collector has to run again before the object can actually be removed. And because finalization might not have happened in a timely fashion, an arbitrary number of garbage collection cycles might have happened while the object was waiting for finalization. This can mean serious delays in actually cleaning up garbage objects, and is why you can get OutOfMemoryErrors even when most of the heap is garbage.
Also read: The Mysterious Phantom Reference
Consider the following code.
public class Foo { private String bar; public Foo(String bar) { this.bar = bar; } public String foo() { return bar; } }
So lets say after the object has been completely dereferenced by the application I want to some how call foo(). Here is some code that I expected to work that would do this with one niggle.
// initialize ReferenceQueue<Foo> queue = new ReferenceQueue<Foo>(); ArrayList< PhantomReference<Foo>> list=new ArrayList<PhantomReference<Foo>>(); for ( int i = 0; i < 10; i++) { Foo o = new Foo( Integer.toOctalString( i)); list.add(new PhantomReference<Foo>(o, queue)); } // make sure the garbage collector does it’s magic System.gc(); // lets see what we’ve got Reference<? extends Foo> referenceFromQueue; for ( PhantomReference<Foo> reference : list) System.out.println(reference.isEnqueued()); while ( (referenceFromQueue = queue.poll()) != null) { System.out.println(referenceFromQueue.get()); referenceFromQueue.clear(); }
PhantomReference takes an instance of Foo and a ReferenceQueue. Since no handles are kept to Foo, it should immediately be dead. Next, tell the VM to collect as there isn’t enough in heap for it to trigger a collection naturally. The first thing I’m going to ask the PhantomReference is; have you been enqueued. In this case the answer will be true. Next I ask the queue for the reference but as you can see, calling get() always returns null. About the only solution that made sense is to wrap the resources or objects you wanted to interact with in a subclass of PhantomReference.
public class FinalizeStuff<Foo> extends PhantomReference<Foo> { public FinalizeStuff(Foo foo, ReferenceQueue<? super Foo> queue) { super(foo, queue); } public void bar() { System.out.println("foobar is finalizing resources"); } }
In this case I’m not going to wrap Foo in the subclass as that would seem to violate the spirit of PhantomReference. Instead I’m going to wrap resources associated with Foo and interact with them. Now I can do this.
// initialize ReferenceQueue<Foo> queue = new ReferenceQueue<Foo>(); ArrayList< FinalizeStuff<Foo>> list = new ArrayList<FinalizeStuff<Foo>>(); ArrayList<Foo> foobar = new ArrayList<Foo>(); for ( int i = 0; i < 10; i++) { Foo o = new Foo( Integer.toOctalString( i)); foobar.add(o); list.add(new FinalizeStuff<Foo>(o, queue)); } // release all references to Foo and make sure the garbage collector does it’s magic foobar = null; System.gc(); // should be enqueued Reference<? extends Foo> referenceFromQueue; for ( PhantomReference<Foo> reference : list) { System.out.println(reference.isEnqueued()); } // now we can call bar to do what ever it is we need done while ( (referenceFromQueue = queue.poll()) != null) { ((FinalizeStuff)referenceFromQueue).bar(); referenceFromQueue.clear(); }
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