Tuesday, August 12, 2008

How can we access an unreachable object in Java?

Can we access an unreachable object in Java?

Yeah... we can. Sounds strange? But, it's true. We can access an unreachable object in Java.

This can be done by overriding the finalize() method and inside the method we can assign the reference 'this' to some other active reference and this way the unreachable object becomes reachable again which can be accessed like any other object. However this is not a good practice and it's seldom used (if at all).

What's finalization in Java and what's it used for?

In Java it's mainly used for doing the postmortem cleanup activities particularly used for reclaiming native resources or any other non-memory resources which can't directly be recollected by the Garbage Collector.

How the finalization of an object happens internally?

protected void finalize() throws Throwable is the signature of the finalize() method in the Object class and whenever any class overrides this method then an object of that class is internally marked by the JVM as finalizable. If such an object becomes unreachable then the Garbage Collector adds it to the JVM's finalization queue. It also makes sure that all the objects reachable from that object are also retained as it can't be sure what all objects may be accessed from inside the finalize() method. Now the object is dequeued from the finalization queue and the finalize() method is executed on that object. Once the control exits from the finalize() method then the object is considered to be finalized which is again tested by the Garbage Collector and if the GC finds that the finalilzed object is unreachable then it reclaims the memory space occupied by that object and also the spaces occupied by other unreachable objects which were retained simply because they were reachable from the finalizable object.

You can easily deduce that such a lengthy process obviously takes time and consequently slows down the performance. Hence it's always advisable to use (override) the finalize() judiciously.

What if the super class is finalizable but not the sub class?

This is not possible as the sub class will automatically become finalizable by inheriting the finalize() method from the super class. Do consider the consequences thoroughly before making any class finalizable otherwise you may end up with memory renetion problems. For example: if a super class is finalizable and sub class which is not explicitly finalizable is having fields occupying huge memory chunks then reclamation of memory occupied by a sub class instance will be delayed till the associated super class instance gets finalized. How to deal with such a situation? Well... you can use composition in stead of inheritance to avoid this problem. This will make sure that reclaimation of only the field of the finalizable class type gets delayed and not the entire object. You can easily have a method disposing the other fields which otherwise would have kept occupying the precious memory for no real purpose. This approach is quite useful in case you are using a third-party finalizable class.

In case you are writing the class yourself then you may break the class into two class - one having the code which really require finalization (i.e., the code which uses native or other non-memory resources) and the other class which simply uses the former class as a member and other non-finalizable members. Now you only need to make the former class finalizable and not the latter.

The bottom line is that don't make any class finalizable unless you have a very good reason behind it and in case you need to make then also make sure that the finalization process doesn't really cause unnecessary memory-renetion.

Is finalization guaranteed? What's the actual contract?

No... it's not guaranteed that the finalization of all the finalizable objects will happen before they are reclaimed so it obviously doesn't make sense to put any other code except the clean-up code inside the finalize() method. In fact finalizer is mainly used for having clean-up code for non-memory and native resources only.

The JVM doesn't guarantee the actual order in which the finalization of the finalizable objects will take place. All the finalizers either from the application or from the libraries are treated equally with no exception.

The JVM doesn't guarantee which thread will invoke the finalize() method of a particular object and only guarantees that the thread which will invoke the method will not have any user-visible synchronization lock at the time of finalize() invocation.

Grrr... so much of non-determinism involved. Yeah... unfortunately it's like this only. So think twice before making any class finalizable.

What if the finalize() method throws any Exception?

If an uncaught exception is thrown from within the finalize() method then it's simply ignored and the finalization of that object terminates immediately.

Any alternative to Finalization in Java?

One possible alternative is to use weak references instead of finalization. This will ensure that the programmer has a complete control over how to reclaim the resources, how to prioritize the reclaimation process (may be based on the availability of a particular native or non-memory resource), etc. We'll discuss about the weak references and about this approach in some other article.

Liked the article? You may like to Subscribe to this blog for regular updates. You may also like to follow the blog to manage the bookmark easily and to tell the world that you enjoy GeekExplains. You can find the 'Followers' widget in the rightmost sidebar.


1 comment:

raghav said...

just one word ..
awesome ..