I\'ve been reading through a lot of the rookie Java questions on finalize()
and find it kind of bewildering that no one has really made it plain that finalize()
class MyObject {
Test main;
public MyObject(Test t) {
main = t;
}
protected void finalize() {
main.ref = this; // let instance become reachable again
System.out.println("This is finalize"); //test finalize run only once
}
}
class Test {
MyObject ref;
public static void main(String[] args) {
Test test = new Test();
test.ref = new MyObject(test);
test.ref = null; //MyObject become unreachable,finalize will be invoked
System.gc();
if (test.ref != null) System.out.println("MyObject still alive!");
}
}
====================================
result:
This is finalize
MyObject still alive!
=====================================
So you may make an unreachable instance reachable in finalize method.
You shouldn't depend on finalize() to clean up your resources for you. finalize() won't run until the class is garbage collected, if then. It's much better to explicitly free resources when you're done using them.
The accepted answer is good, I just wanted to add that there is now a way to have the functionality of finalize without actually using it at all.
Look at the "Reference" classes. Weak reference, Phantom Reference & Soft Reference.
You can use them to keep a reference to all your objects, but this reference ALONE will not stop GC. The neat thing about this is you can have it call a method when it will be deleted, and this method can be guaranteed to be called.
As for finalize: I used finalize once to understand what objects were being freed. You can play some neat games with statics, reference counting and such--but it was only for analysis, but watch out for code like this (not just in finalize, but that's where you are most likely to see it):
public void finalize() {
ref1 = null;
ref2 = null;
othercrap = null;
}
It is a sign that somebody didn't know what they were doing. "Cleaning up" like this is virtually never needed. When the class is GC'd, this is done automatically.
If you find code like that in a finalize it's guaranteed that the person who wrote it was confused.
If it's elsewhere, it could be that the code is a valid patch to a bad model (a class stays around for a long time and for some reason things it referenced had to be manually freed before the object is GC'd). Generally it's because someone forgot to remove a listener or something and can't figure out why their object isn't being GC'd so they just delete things it refers to and shrug their shoulders and walk away.
It should never be used to clean things up "Quicker".
To highlight a point in the above answers: finalizers will be executed on the lone GC thread. I have heard of a major Sun demo where the developers added a small sleep to some finalizers and intentionally brought an otherwise fancy 3D demo to its knees.
Best to avoid, with possible exception of test-env diagnostics.
Eckel's Thinking in Java has a good section on this.
Be careful about what you do in a finalize()
. Especially if you are using it for things like calling close() to ensure that resources are cleaned up. We ran into several situations where we had JNI libraries linked in to the running java code, and in any circumstances where we used finalize() to invoke JNI methods, we would get very bad java heap corruption. The corruption was not caused by the underlying JNI code itself, all of the memory traces were fine in the native libraries. It was just the fact that we were calling JNI methods from the finalize() at all.
This was with a JDK 1.5 which is still in widespread use.
We wouldn't find out that something went wrong until much later, but in the end the culprit was always the finalize() method making use of JNI calls.
Edit: Okay, it really doesn't work. I implemented it and thought if it fails sometimes that's ok for me but it did not even call the finalize method a single time.
I am not a professional programmer but in my program I have a case that I think to be an example of a good case of using finalize(), that is a cache that writes its content to disk before it is destroyed. Because it is not necessary that it is executed every time on destruction, it does only speed up my program, I hope that it i didn't do it wrong.
@Override
public void finalize()
{
try {saveCache();} catch (Exception e) {e.printStackTrace();}
}
public void saveCache() throws FileNotFoundException, IOException
{
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("temp/cache.tmp"));
out.writeObject(cache);
}