We all know the basic statement that finalize() method is called by garbage collector thread before reclaiming the memory allocated to the object. In this post, we will drill down more deeply into this method.
Sections in this post:
- finalize() execution is not guaranteed at all (with example)
- Other reasons for not using it
- finalize() add heavy penalty in performance
- Guide for correct usage
finalize() execution is not guaranteed at all (with example)
Lets prove it using a program. I have written a simple java runnable with one print statement in each block i.e. try-catch-finally-finalize. I have also created another class which will create 3 instances of this runnable and then we will see the execution path.
public
class
TryCatchFinallyTest
implements
Runnable {
private
void
testMethod()
throws
InterruptedException
{
try
{
System.out.println(
"In try block"
);
throw
new
NullPointerException();
}
catch
(NullPointerException npe)
{
System.out.println(
"In catch block"
);
}
finally
{
System.out.println(
"In finally block"
);
}
}
@Override
protected
void
finalize()
throws
Throwable {
System.out.println(
"In finalize block"
);
super
.finalize();
}
@Override
public
void
run() {
try
{
testMethod();
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
ublic
class
TestMain
{
@SuppressWarnings
(
"deprecation"
)
public
static
void
main(String[] args) {
for
(
int
i=
1
;i<=
3
;i++)
{
new
Thread(
new
TryCatchFinallyTest()).start();
}
}
}
Output:
In
try
block
In
catch
block
In
finally
block
In
try
block
In
catch
block
In
finally
block
In
try
block
In
catch
block
In
finally
block
Now, next question is, can we force it to execute?
Answer is yes. Yes, we can. Using Runtime.runFinalizersOnExit(true);
public
class
TestMain
{
@SuppressWarnings
(
"deprecation"
)
public
static
void
main(String[] args) {
for
(
int
i=
1
;i<=
3
;i++)
{
new
Thread(
new
TryCatchFinallyTest()).start();
Runtime.runFinalizersOnExit(
true
);
}
}
}
Output:
In
try
block
In
catch
block
In
finally
block
In
try
block
In
try
block
In
catch
block
In
finally
block
In
catch
block
In
finally
block
In finalize block
In finalize block
In finalize block
There is another method also: Runtime.getRuntime().runFinalization(); But, it only guarantees that GC will make best efforts. Even in our program it is not able to run finalize method for all 3 threads.
Moving forward, we have used Runtime.runFinalizersOnExit(true); Well, this is another pit. This method has already been deprecated in JDK, with following reason:
“This method is inherently unsafe. It may result in finalizers being called on live objects while other threads are concurrently manipulating those objects, resulting in erratic behavior or deadlock.”
So, in one way we can not guarantee the execution and in another way we the system in danger. Better, don’t use it.
Other reasons for not using it
1) finalize() methods do not work in chaining like constructors. It means like when you call a constructor then constructors of all super classes will be invokes implicitly. But, in case of finalize methods, this is not followed. Super class’s finalize() should be called explicitly.
Suppose, you created a class and wrote its finalize method with care. Someone comes and extend your class and does not call super.finalize() in subclass’s finalize() block, then super class’s finalize() will never be invoked anyhow.
2) Any Exception thrown by finalize method is ignored by GC thread and it will not be propagated further, in fact it will not be logged in your log files. So bad, isn’t it?
finalize() add heavy penalty in performance
In Effective java (2nd edition ) Joshua bloch says, "Oh, and one more thing: there is a severe performance penalty for using finalizers. On my machine, the time to create and destroy a simple object is about 5.6 ns. Adding a finalizer increases the time to 2,400 ns. In other words, it is about 430 times slower to create and destroy objects with finalizers."
I also tried above analysis on my system but i was not able to get that much difference. Although, there are some difference for sure. But that was around 30% on original time. On time critical systems, it is also a big difference.
Guide for correct usage
After all above arguments, if you still find a situation where using finalize() is essential, then cross check below points:
- Always call super.finalize() in your finalize() method.
- Do not put time critical application logic in finalize(), seeing its unpredictability.
- Do not use Runtime.runFinalizersOnExit(true); as it can put your system in danger.
- Try to follow below template for finalize method
@Override
protected
void
finalize()
throws
Throwable
{
try
{
//release resources here
}
catch
(Throwable t){
throw
t;
}
finally
{
super
.finalize();
}
}
Happy Learning !!
Reference: http://howtodoinjava.com/2012/10/31/why-not-to-use-finalize-method-in-java/