Wednesday 26 February 2014

Misconceptions about Object.finalize()

I have been studying Java for about 6 years now and all along I have dissected something interesting about it at various levels. To be more general, I think the beauty of OOP lies in its inherent simplicity to hide relevant complexities and one does not unlock these complexities till the time he explicitly starts working on them.

I had always learnt that the Object.finalize() method is used to clean up resources before an object is garbage collected by the JVM. My professor simplified it all the more for me and my then innocent friends who were led to believe that in simple terms, "Object.finalize() is just the same thing as Destructors in C++". Woah, now, that's one of those instances of reckless simplification founded upon specious reasoning.

I will just explain what it really is and nothing more. Object.finalize() is a function or a method that may be overriden by any Java object (provided its class implementation provides the necessary overriding definition, that is) and this method is called by the JVM when it notes that no more references exist to this object and that it may be safely garbage collected. 

The finalize() method definition itself may include code  to cleanup resources that are not going to be used, say, file.close() method, for example. If the method has been overriden, then the JVM invokes the finalize() before the object itself will be deallocated, that is, the finalize() is in effect, the last operation that will be performed by an object along its lifecycle from birth to termination.

Now there is an essential caveat here that needs special attention. For one thing, never rely on finalize() to do anything that you believe is critical from the system functioning perspective. Well, that is because Object.finalize() is called by a JVM GC (Garbage Collector) thread while the JVM itself provides no real guarantees in regard to whether the finalize() will ever be called. 

Now, what does this really mean? It does sound fairly paradoxical in that on the one hand, you hear it will be called by the JVM before the object will be deallocated and on the other, you note that the JVM cannot guarantee that it will be called ever. Well, here is where a little extra information can help. Well, we must recollect that we can never ascertain when exactly the JVM does its garbage collection or to be more clear, one can never guess when the JVM GC thread itself will be scheduled and eventually dispatched. So, it is safe to assume that at times, the application or the program itself will run from start to completion and the JVM GC thead has not managed to run during the application program life cycle. In such cases, those objects used in the program will only be deallocated after the program itself has terminated and when the JVM GC thread will on its part, reclaim the space used by those concerned objects. So, it's now evident here that the finalize() has not been executed for the program has terminated prior to its invocation by the JVM.

So when do we really use finalize()? Well, the general idea is that do not use it to accomplish tasks or execute operations that determine the fate of the application itself. It is safe to use it to accomplish less critical functions, for say, logging information that could later be used for debugging. Here, the key idea is to never really rely on it to do anything, for that may not necessarily serve the purpose.

Now, with regard to some drawing parallels with the the C++ destructor, I must add that the destructor is guaranteed to be called during the lifetime of the program. So yes, you may use to perform some last minute work that will need to be done prior to destruction of the object itself. It's the presence of this guarantee in the case of destructors and the absence of it in the case of finalize() that makes all the difference. 

No comments:

Post a Comment