Muhammad Khojaye is an experienced consultant who has worked on both large scale Agile development projects for top financial clients and public sector innovative research and development projects. In his spare time, Muhammad likes to work on independent open source programs. Muhammad is a DZone MVB and is not an employee of DZone and has posted 13 posts at DZone. You can read more from them at their website. View Full User Profile

Finalization and Phantom References

05.07.2010
| 27327 views |
  • submit to reddit

Memory management is done automatically in Java. The programmer doesn't need to worry about reference objects that have been released. One downside to this approach is that the programmer cannot know when a particular object will be collected. Moreover, the programmer has no control over memory management. However, the java.lang.ref package defines classes that provide a limited degree of interaction with the garbage collector. The concrete classes SoftReference, WeakReferenceand PhantomReference are subclasses of Reference that interact with the garbage collector in different ways. In this article we will discuss the functionality and behavior of the PhantomReference classes and see how it can be used.

Problem with Finalization

To perform some postmortem cleanup on objects that garbage collector consider as unreachable, one can use finalization. This feature can be utilized to reclaim native resources associated with an object. However, finalizers have many problems associated.

Firstly, we can’t foresee the call of finalize(). Since the Garbage Collection is unpredictable, the calling of finalize() cannot be predicted. There is no guarantee that the object will be garbage collected. The object might never become eligible for GC because it could be reachable through the entire lifetime of the JVM. It is also possible that no garbage collection actually runs from the time the object became eligible and before JVM stops.

Secondly, Finalization can slowdown an application. Managing objects with a finalize() method takes more resources from the JVM than normal objects.

As per doc,

You should also use finalization only when it is absolutely necessary. Finalization is a nondeterministic -- and sometimes unpredictable -- process. The less you rely on it, the smaller the impact it will have on the JVM and your application

 In Effective Java, 2nd ed., Joshua Bloch says,

there is a severe performance penalty for using finalizers... So what should you do instead of writing a finalizer for a class whose objects encapsulate resources that require termination, such as files or threads? Just provide an explicit termination method, and require clients of the class to invoke this method on each instance when it is no longer needed.

In short, Finalize() isn't used often, and also there is no much reason to use it. If we have a class with methods like close() or cleanup() and that should be called once user done with the object then placing these methods call in finalize() can be used as a safety measure, but not necessary.

Phantom Reference

phantom reachable, phantomly reachable

An object is phantom reachable if it is neither strongly nor softly nor weakly reachable and has been finalized and there is a path from the roots to it that contains at least one phantom reference.

The PhantomReference constructor accepts two arguments:

referent - the object the new phantom reference will refer to
q - the reference is registered with the given queue.

The argument q represents the instance of the ReferenceQueue class. If the garbage collector determines that the referent of a phantom reference is phantom reachable, then the PhantomReference will be added to this ReferenceQueue. You can then retrieve the PhantomReference by using the remove() methods of the ReferenceQueue class.

Consider the following example,

ReferenceQueue q = new ReferenceQueue();
PhantomReference pr = new PhantomReference(object, referenceQueue);

// Later on another point
Reference r = q.remove();

// Now, clear up any thing you want

PhantomReference, when to use?

Phantom Reference can be used in situations, where sometime using finalize() is not  sensible thing to do.This reference type differs from the other types defined in java.lang.ref Package because it isn't meant to be used to access the object, but as a signal that the object has already been finalized, and the garbage collector is ready to reclaim its memory.

As per API doc,

Phantom reference objects, which are enqueued after the collector determines that their referents may otherwise be reclaimed. Phantom references are most often used for scheduling pre-mortem cleanup actions in a more flexible way than is possible with the Java finalization mechanism.

People usually attempt to use finalize() method to perform postmortem cleanup on objects which usually not advisable. As mentioned earlier, Finalizers have an impact on the performance of the garbage collector since Objects with finalizers are slow to garbage collect.

Phantom references are safe way to know an object has been removed from memory. For instance, consider an application that deals with large images. Suppose that we want to load a big image in to memory when large image is already in memory which is ready for garbage collected. In such case, we want to wait until the old image is collected before loading a new one. Here, the phantom reference is flexible and safely option to choose. The reference of the old image will be enqueued in the ReferenceQueue once the old image object is finalized. After receiving that reference, we can load the new image in to memory.

Similarly we can use Phantom References to implement a Connection Pool. We can easily gain control over the number of open connections, and can block until one becomes available.

Reference Objects and Garbage Collection

Soft Reference can be garbage collected after there are no strong references to the referent. However, it typically retained until memory is low. All softly reachable objects will be reclaimed before an OutOfMemoryException is thrown. Therefore, it can be used to implement caches of objects that can be recreated if needed. 

Weak Reference can be garbage collected when there are no strong or soft references to the referent. However, unlike Soft Reference, they are garbage collected on a gc even when memory is abundant. They often can be used for “canonical mappings” where each object has a unique identifier (one-to-one), and in collections of “listeners”

On the other hand, Phantom Reference, can be garbage collected once there are no strong, soft or weak references to the referent. When object is phantomly reachable, it means the object is already finalized but not yet reclaimed, so the GC enqueues it in a ReferenceQueue for post-finalization processing.

As per Java Doc,

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 PhantomReference is not automatically cleared when it is enqueued, so when we remove a PhantomReference from a ReferenceQueue, we must call its clear() method or allow the PhantomReference object itself to be garbage-collected. 

Summary

In short, we should avoid finalize() as much as possible. There is no guarantee if the finalize() method will be called promptly following garbage collection, or even it will be called. If the finalize method runs for a long time, it can delay execution of finalize methods of other objects. Instead of relying on finalize(), we can use reference types define in java.lang.ref package.

Beside java.lang.ref package, Google collection library also provide some alternatives. For example, FinalizablePhantomReference extends java.lang.ref.PhantomReference, deals with processing the ReferenceQueue and call back a convenient method finalizeReferent(). So if we want to do some cleanup operation when an object is claimed by the garbage collector (GC) then we just need to override the finalizeReferent() method.

Resources

Garbage Collection

PhantomReference

http://docstore.mik.ua/orelly/java-ent/jnut/ch13_01.htm

Understanding Weak References


- See more at: http://muhammadkhojaye.blogspot.com/2010/05/understanding-phantom-references.html 

Published at DZone with permission of Muhammad Khojaye, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Wujek Srujek replied on Sat, 2010/05/08 - 5:02am

Nice article, but it lacks examples. The one snippet that is included doesn't actually tell you anytning about how to use this feature. When do you call the q.remove()? Whevener you want? You get some notification?

Mikael Grev replied on Sat, 2010/05/08 - 5:21am

Something I've wondered is how one could use Weak or Phantom references to revive an object. What I want is to know when there are no strong (and/or Weak, Soft) references to an object and then re-establish it as a normal object by referencing it again using a strong reference.

That would be the killer use case for clean and simple object pool caches. I know, they are usually not needed, but I want one for big ByteBuffers and my current implementation uses a manual deregister approach.

So, does anyone know of a working way to get a reference back right before it is being garbage collected?

Cheers,
Mikael Grev

Clemens Eisserer replied on Sat, 2010/05/08 - 5:32am in response to: Mikael Grev

> Something I've wondered is how one could use Weak or Phantom references to revive an object

 Unfourtunatly thats not possible. Did some "research" in this area because of a distributed GC I implemented, however the only possible way to do it is using finalizers - and even that way its quite complex.

So short story ... I decided against using finalizers.

 

- Clemens

Mikael Grev replied on Sat, 2010/05/08 - 5:39am in response to: Clemens Eisserer

Thanks Clemens, saves me from reiterating this. :)

Kirk Pepperdine replied on Mon, 2010/05/10 - 5:41am

Josh is right, using finalization does come with a performance penalty. However he doesn't explain where that cost is coming from. A fair portion of it comes from the use of PhantomReference in the finalization process. The other portion comes in having to GC an object (at least) twice, once to say "it's dead, finalize it", and then a second time to actually GC the object. And you have to deal with it in the reference queue. I don't see any practical way of knowing when to run "finalization" without the collector being involved. Certainly the costs will be approximately the same. One other point, using any alternate reference type causes GC to work harder as it has to perform extra calculations to determine eligibility for collection. Again, using PhantomReference yourself will not save you anything here. Regards, Kirk

Muhammad Khojaye replied on Tue, 2010/05/11 - 12:35pm

It is correct that PhantomReference also might never run, but unlike finalizer, it can't call methods on or resurrect finalized objects. Similarly, in these unpredictable situations, again phantom references have an advantage over finalizers since cleanup is always under your control. With finalizers you can use System.gc() in the hope that the collector would work to get objects, but again there's no guarantee.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.