...
- There is no fixed time for finalizers to get executed, which again is JVM dependent: The only thing that is guaranteed is that if at all a finalizer gets executed, it will be executed before the garbage collector's runsecond cycle. An object may become unreachable and yet its finalizer may not execute for an arbitrarily long time. Nothing of time-critical nature should be run in the
finalize
method, for instance, closing file handles is not recommended.
- Do not depend on a finalizer for updating critical persistent state: It is possible for the JVM to terminate without invoking the finalizer on an unreachable object. As a result it is not advisable to use any lock or sharing based mechanisms within a finalizerFinalization on process exit is also not guaranteed. Methods such as
System.gc
,System.runFinalization
,System.runFinalizersOnExit
andRuntime.runFinalizersOnExit
are either just marginally better or have been deprecated due to lack of safety and deadlock causing effects.
Wiki Markup According to the Java Language Specification: \[[JLS 05|AA. Java References#JLS 05]\] Section 12.6.2:
Wiki Markup The Java programming language imposes no ordering on finalize method calls. Finalizers \[of different objects\] may be called in any order, or even concurrently.
This can be a problem as slow running finalizers tend to block others in the queue.
- Effect of uncaught exceptions: An uncaught exception thrown during finalization is ignored. The finalization process itself stops immediately so it fails to accomplish its purpose.
...
- It is also imprudent to use finalizers for reclaiming scarce resources by inviting garbage collection. Garbage collection usually depends on memory related traits and not on the scarcity of a particular resource. Thus, if memory is available aplenty, there is no reason for the scarce resource to not get exhausted despite the use of a finalizer. See FIO34-J. Ensure all resources are properly closed when they are no longer needed and CON02-J. Facilitate thread reuse by using Thread Pools for more on handling resources correctly.
- A common myth is that finalizers aid garbage collection. On the contrary, they increase garbage collection time and introduce space overheads. They also fail to respect the modern generational garbage collectors. Another trap unfolds while trying to finalize reachable objects, an exercise that is always counterproductive.
Wiki Markup It is not advisable to use any lock or sharing based mechanisms within a finalizer due to the inherent dangers of deadlock and starvation. On the other hand, it is also easy to miss that there can be synchronization issues with the use of finalizers even if the source program is single-threaded. This is because the {{finalize()}} methods are called from their own threads. If a finalizer is inevitable, the cleanup data structure should be protected from concurrent access (See \[[Boehm 05|AA. Java References#Boehm 05]\]).
Exceptions
OBJ02-EX1: Sometimes it is necessary to use finalizers especially while working with native objects/code. This is because the garbage collector cannot re-claim memory from code written in another language. Also, the lifetime of the objects is often unknown. Again, the native process must not perform any critical jobs that require immediate resource deallocation.
...
Code Block |
---|
public class Foo { // The finalizeGuardian object finalizes the outer Foo object private final Object finalizerGuardian = new Object() { protected void finalize() throws Throwable { // Finalize outer Foo object } }; //... } |
The ordering problem can be dangerous while dealing with native code. For example, if object A
references object B
(either directly or reflexively) and the latter gets finalized first, A
's finalizer may end up dereferencing dangling native pointers. To impose an explicit ordering on finalizers, make sure that B
is reachable before A
's finalizer has concluded. This can be done by adding a reference to B
in some global state variable and removing it as soon as A
's finalizer gets executed. An alternative is to use the java.lang.ref
references.
If a superclass defines a finalize
method, make sure to decouple the objects that can be immediately garbage collected from those that depend on the finalizer. In the MyFrame
example, the following code will ensure that the buffer
doesn't persist longer than expected.
...
Wiki Markup |
---|
\[[JLS 05|AA. Java References#JLS 05]\] Section 12.6, Finalization of Class Instances
\[[API 06|AA. Java References#API 06]\] [finalize()|http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html#finalize()]
\[[Bloch 08|AA. Java References#Bloch 08]\] Item 7, Avoid finalizers
\[[Darwin 04|AA. Java References#Darwin 04]\] Section 9.5, The Finalize Method
\[[Flanagan 05|AA. Java References#Flanagan 05]\] Section 3.3, Destroying and Finalizing Objects
\[[Coomes 07|AA. Java References#Coomes 07]\] "Sneaky" Memory Retention
\[[Boehm 05|AA. Java References#Boehm 05]\] |
...
OBJ01-J. Understand how a superclass can affect a subclass 06. Object Orientation (OBJ) OBJ03-J. Be careful about final reference