Several people in recent past have asked me the functionality and need of finalize() method in Java, hence the post 🙂 :
BEWARE: Frankly finalize() is something that you should avoid using. The disadvantages and risk it carries are far more than the need of it. One can absolutely avoid it in 95% of the cases.
finalize() is a means to execute final bit of code just before the object is ready for garbage collection ( when the object has no strong reference to it).
So when should it be used?
Only in the present two cases:
1) As a safety to make sure that some service is closed down or some desired final change is made. For example InputStream class uses it to close down the i/o stream. That is for example you have made an instance of BufferedInputStream. Manually after using it one is suppose to close() it. But because one can forget to do that, finalize() act’s as a safety net to close() the stream.
2) While using Native’s. Because garbage collector has no control over native objects, finalize() can be used as a means to reclaim it.
Apart from the above two cases never use it. To understand why? we need to understand the functioning and lifecycle of an object.
Introduction: There is a separate daemon thread called as finalizer thread which is responsible for calling finalize() method . Finalization queue is the queu where objects which are ready to be called finalize() method are placed.
- When an Object is created, JVM checks if the object has a finalize() method. If it has then it internally notes that this particular object has finalize() method.
- When an object is ready for garbage collection, then the garbage collector thread checks if this particular object has finalize() from table mentioned in (1).
2a) If it doesn’t then it is sent for garbage collection.
2b) It is has, then it is added to the finalization queue. And it removes the entry of the object from the table (1).
- Finalizer thread keeps polling the queue. For every object in the queue, its finalize() method is called.
- After calling the finalize() cycle from (2) is again repeated. If this object still has no strong reference, then sent for GC. If it has then ALWAYS (2a) is called because the entry was deleted in (2b). Basically finalize() method is only called once.
So what’s the issue with the above cycle?
- From (1). Its take extra time in object creation. Memory allocation in Java is 5x to 10x faster than malloc/calloc etc. All the time gained is lost in the procedure of noting the object in the table etc. I once tried it. Create 100000 objects in a loop and measure the time taken for program to terminate in 2 cases: One with no finalize(), Second with finalize(). Found it to be 20% faster.
- From (2b): Memory Leakage and Starvation. If the object in the queue has references to a lot of memory resources, then all those objects wont get freed unless this object is ready for GC.If all the objects are heavy weight objects, then there can be a shortage.
- From (2b): Because finalize() is called only once, what if in teh finalize() you had a strong reference to “this” object. Next time the object’s finalie() is never called hence can leave the object in an inconsistent state.
- If inside finalize() an exception is thrown, it is ignored.
- You do not know when finalize() is called as you have no control over when GC is called. Sometimes it might happen that you are printing the value’s in finalize() but the output is never shown, because your program might have got terminated by the time finalize() is called.
Hence avoid using it. Instead create a method say dispose() which will close the necessory resources or for final log etc.