Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the practical use of phantom references - JAVA?

Tags:

java

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

like image 434
Tarun Kundhiya Avatar asked Nov 02 '15 11:11

Tarun Kundhiya


People also ask

What is a weak reference and how could it be useful to us?

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.

What are strong soft weak and phantom references in Java?

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.

Why do we use weak references?

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.

What's the difference between Softreference and Weakreference in Java?

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.


1 Answers

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();
}
like image 85
Rahul Tripathi Avatar answered Sep 18 '22 12:09

Rahul Tripathi