While writing an article about using phantom links, I needed to refer to the inconvenience arising from working with the finalize method. In addition, I believe that this topic will be useful to all java developers who are beginning java, and some points will not be superfluous to remember even experienced programmers, because using the finalize method is very simple, which cannot be said about searching for the last thing. Even if you firmly believe never to use the finalize method, this does not mean that your previous colleagues did not use them, and you do not need to understand how they work. So, let's go from the obvious to the less intuitive.
Since the finalize method is called at the first garbage collection following the moment when your object became unreachable, it is quite possible that it will not be called at all, because your application can finish its work without reaching this garbage collection itself. Although, of course, there is one remarkable method System.runFinalizersOnExit (true) , which causes that at the start of the program, the finalize method will still work for objects that are already unattainable during the correct shutdown of the application.
The JVM specification does not define the question of the multithreading method of finalization. In HotSpot, all finalize methods will be called sequentially in one Finalizer thread. However, if you call the System.runFinalization () method, another thread will be born that will block the current one and will execute the finalize methods if the appropriate objects are in the queue. And this may well occur parallel to the main stream Finalizer.
Redefining the finalize method significantly extends the lifetime of the object after death, since it will not be removed from memory until the second garbage collection. And considering the first two points, if you have a finalize method that is heavy and / or there are a lot of such objects, then objects can hang for a long time in the finalization phase and continue to occupy space in the memory.
During the execution of the finalize method, you can restore an object reference, for example, by placing it in some static context, thereby resurrecting the object. The danger of such a maneuver is that the second time the method finalize this object will never be called. Therefore, if for some reason you really need to resurrect this object, then it’s better to create a copy inside the finalize method.
One of the most unpleasant problems encountered when using the finalize method is reordering. Imagine that you have two objects with an overridden finalize method, one of which refers to the other. So, if these objects have become unattainable, then the order of calling the methods of finalization will occur in a random order. Thus, you will have the potential danger of invoking some method on an already finalized object from the finalize method of another object and getting an error. And the problem will not occur on every object, which will add a headache when debugging.
According to Joshua Bloch, author of the famous book “Effective Java: Programming Language Guide”, for objects with a redefined method finalize, allocation and assembly can occur 430 times slower than a regular object.
Any exceptions thrown in the method body will be ignored.
One should not forget to call super.finalize () at the end of the method. And given the previous point, this should be done in the finally block.
According to the above, the use of the finalize method should be avoided if possible; rather, you should not rely on it. It is better to free resources programmatically, and in the finalize method to log if this was not done for some reason, in order to find and fix the problem in time. If, however, you still need to release resources during the assembly of the object, then most likely it is better to use phantom links for this .