Finalize Guardian, once again.

Tags:

To archtyrael and others. ;-)

Finalize Guardian, once again.

In this article, I will talk about finalize guardian pattern and its purpose; why do we have to concern about it.

Joshua Bloch, who was JAVA API architect, wrote a brilliant book “EFFECTIVE JAVA.”, and finalize guardian idiom was introduced in that book. Type safe enum, which was also covered in his book, was adpoted in JDK 1.5, adding some nice features on his own idea.

Note that codes in this article should be considered in the context of inheritance. Though it is proved that inheritance is worse than composition,inheritance is still widely used. And implementation inheritance, on the contrary to interface inheritance, is one of the most important feature of OOP paradigm to reuse legacy codes.

However, you must note that decorator pattern may meet the need of code reuse in practice, and it is preferable to inheritance.

Please refer to PROGRAMMING LANGUAGE by SEBESTA for the explanation of implementation/interface inheritance.

1. Constructor and Destructor

As you know, objects can be inherited. Suppose that you have two class like:

#include

using namespace std;

class Parent {
public:
Parent() {
cout << "Parent Construction" << endl; } ~Parent() { cout << "Parent Destruction" << endl; } }; class Child: public Parent { public: Child() { cout << "Child construction" << endl; } ~Child() { cout << "Child destruction" << endl; } }; int main() { Child c; } [/code] What do you think the result of this program? In gcc-c++-3.2.3-4 and Microsoft Visual Studio .NET, this program will shows you: [code lang="cpp"] [pool007@dke tmp]$ ./a.out Parent Construction Child construction Child destruction Parent Destruction [/code] However, you must know the fact that this is not always the case how C++ compilers runs the code. In C/C++ ISO standard, it is not defined what the compilers do when the destructor of parent class is not virtual. If the constructor of child class does not call any constructor of parent class, default constructor (constructor without any parameters) is called. On the contrary, if the destructor of child class does not explicitly call destructor and the destructor of the parent class is not virtual, we don't know what the program will do. Standard says that to call the destructor of parent class automatically, destructor of parent class should be virtual. This fact also applies to JAVA and .NET. You must call finalize of parent class if you want to finalize your parent class. 2. Destructors that does not work. 2.1. Resurrection Suppose that you have put your class instance into hashtable like: [code lang="java"] fHashtable.put(key, your_class); fHashtable.put(key, class_which_is_implemented_by_others); [/code] What if the destructor of class class_which_is_implemented_by_others is programmed like this: [code lang="java"] void finalize() { // to clear me, I have to call your_class instance your_class.some_method(); } [/code] Suppose that garbage collector have removed your_class from heap. And then, to garbage collect class_which_is_implemented_by_others, the virtual machine have to use your class. That is to say, your class is resurrected. Then the garbage collector will finalize your_class once again. This the problem so called 'resurrection.' 2.2. Cursed Cycles It is also possible your_class, by any chance, called class_which_is_implemented_by_others to clean itself. Things become complicated in this situation. Due to the cycle of finalize methods and continuous resurrections, garbage collector can not stop the program. 2.3. Infinite loop And code like this is also possible: [code lang="java"] void finalize() { while (true) { job(); } } [/code] This finalize method will never end. 2.4. Uncaught exception Consider the following: [code lang="java"] void finalize() { throw new XXXException(); // This Exception inherited RuntimeException } [/code] You can easily guess that finalize method caller would be coded like: [code lang="java"] for(item in list) { item.finalize(); } [/code] In this case, not all finalize will be called because the for-loop is breaked due to the uncatchable exception. 3. How finalize are called? To prevent such situations of Chap 2, in .NET and JAVA environment, calling finalize is not guranteed. What makes things more complicated is the fact that thread which garbage collect objects and thread which call finazlie is different. Hence, we don't know whether the objects are finalized before garbage collected. Also, these thread execution order is not guranteed. 4. What I have to do, then? 4.1. Dispose pattern DO NOT RELY ON FINALIZE. Instead, use dispose pattern: [code lang="java"] public interface Dispose { public void dispose(); } public class MyClass implements Dispose { ... public void dispose() { // clean } } .... public static void main(String[] args) { MyClass mc = new MyClass(); mc.dispose(); } ... [/code] The above code will work perfectly because you explicitly do the finalization. In managed environment(by managed environment, I mean JAVA or .NET virtual machine), memory is controlled by virutal machine. However, more precious resources such as network connection, file, and database connections are not controlled by the VM. You have to manage those resources. One of the example of explicitly managing resources is java.sql.Connection. That class provides close() method to close the datbase connection. As database connection is very high-cost(It tooks lots of time, and there are limited number of connections.), programmers must call close() method after they finished their job. 4.2. finalize is of no use? Finalize can be the last place of resource releasing. Suppose that users forgot to call Close() method. For such situations, you must make your finalize method like: [code lang="java"] public void finalize() { Close(); } [/code] Though, as I said before, calling finalize is not guranteed. Making finalize like this is only for the purpose of safety net. 5. finalize and inheritance Now, we are prepared to talk about finalize guardian. The form of this pattern is: [code lang="java"] public class MyClass { public Object o = new Object() { public void finalize() { dispose(); } } public void dispose() { ... } } [/code] Suppose that other user inherited your class like: [code lang="java"] public class Child extends MyClass { public void doJob() { ... } public finalize() { doJob(); } [/code] Unfortunately, he or she did not call the destructor of the parent. So, finalize method of MyClass will never be called; of course, the destructor can be called in some implementation of virtual machine. This is the place where finalize guardian come into play. To garbage collect instance of MyClass, VM will garbage collect variable o of MyClass. And to garbage collect the o, dispose() will be called automatically. 6. Conclusion Finalize guardian is the last resort to gurantee finalizing objects to some unguranteed degree. Hope this helps. References - Effective JAVA - Effective C++

Comments

4 responses to “Finalize Guardian, once again.”

  1. 민구 Avatar
    민구

    아 이제 이 내용은 그만. 이걸로 더 안쓸생각. gotdotnet에 보면 Dispose 패턴을 상속계층에서 잘 사용하기 그런 아티클이 있지만, 찾기 어려움… 찾아보시길 ^^

  2. Kausik Ghatak Avatar

    Java Lang Spec (3rd Ed.)guarantees that finalize() method will always be invoked by the JVM before the object can be reclaimed.

  3. mkseo Avatar
    mkseo

    Kaushik, thank you for great info! That’s very good to hear that we have finalize called.

    However, I still think finalize is far from ideal. finalize is called from a thread that could be the different one from the last thread who hold the object. Thus, the finalization thread could be the one on a CPU other than the last CPU who hold the object.

    This means that we need to get synchronization on the soon-will-be-reclaimed object to access the latest status of member variables of the object.

    Unfortunately, holding a lock on being-reclaimed object, according to the spec, will result in resurrection of the object.

    What a sad story…

  4. Chris Avatar
    Chris

    Thanks for explaing the part on finalize guardians.

    Currently i’m also reading the book Effective Java from Joshua Block and your blog about the subject did clarify a lot..

Leave a Reply

Your email address will not be published. Required fields are marked *