Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java finalizer guardian does not seem to work?

Tags:

java

finalize

I have a super class with telescoping constructors with a finalize() method. To protect against subclasses forgetting to invoke super.finalize, I have written a finalizer guardian (EJ Item 7 ) like so.

public class Super {

    public Super() {}

    {
        Object finalizerGuardian = new Object() {
            @Override
            protected void finalize() {
                System.out.println("Finalizer guardian finalize");
                Super.this.finalize();
            }
        };
    }

    protected void finalize() {
        System.out.println("Super finalize");
    }

}

Here is a sample subclass --

public class Sub extends Super {

    public Sub() {}

    protected void finalize() {
        System.out.println("Sub finalize");
    }

    public static void main(String[] args)
            throws InterruptedException {
        if (1 == 1) {
            Sub s1 = new Sub();
        }
        Runtime.getRuntime().gc();
        Thread.sleep(10000);
    }
}

When the s1 object goes out of scope, the finalizer guardian's finalize() gets called, and I get the SYSO from the subclass's finalize method, but never get the one from super's finalize.

I'm confused. Am I misunderstanding something fundamentally?

Disclaimer : I realize finalizers are dangerous and not advisable, etc. Still trying to understand the problem here.

like image 613
Kal Avatar asked Aug 12 '11 14:08

Kal


People also ask

What problem does the finalizer guardian in Java protect against?

It solves the problem of the sub-class forgetting to call the finalize method of the super-class. This pattern works by attaching an extra instance with overridden finalize to your super-class.

Why it is recommended to avoid using the finalize () method?

You shouldn't implement a Finalize method for managed objects because the garbage collector releases managed resources automatically. If a SafeHandle object is available that wraps your unmanaged resource, the recommended alternative is to implement the dispose pattern with a safe handle and not override Finalize.

Why we should not use finalize in Java?

Other Reasons for Not Using finalize() It means when you call a constructor then constructors of all superclasses will be invoked implicitly. But, in the case of finalize() methods, this is not followed. Ideally, parent class's finalize() should be called explicitly but it does not happen.

Who invokes finalize method in Java?

Finalization. Garbage collector always invokes finalize() method in java to perform clean-up activities before destroying any object. This process of performing clean-up activities using finalize() method is called finalization.


4 Answers

Effective Java's finalizer guardian should perform the necessary finalization logic itself (for example, call some method of Super that performs the actual finalization) rather than call the finalize() method, because in your case Super.this.finalize(); actually calls the overriden method from the subclass.

Also note that finalizer guardian should be a field of the class:

public class Super {
    private final Object finalizerGuardian = new Object() {
            @Override
            protected void finalize() {
                Super.this.doFinalize();
            }
    };

    private void doFinalize() {
        System.out.println("Super finalize");
    }
}
like image 81
axtavt Avatar answered Oct 12 '22 10:10

axtavt


You are overloading the Super.finalize() method in Sub. That's why it's not being called.

So when you in "finalizerGuardian" call Super.this.finalize(); you are actually calling Sub.finalize().

like image 40
dacwe Avatar answered Oct 12 '22 09:10

dacwe


AS others have already said dynamic dispatch is your problem here. BUT there's one other major bug in your code as far as I see: Your finalizerGuardian is only defined inside the initialization block, this means that as soon as the object is initialized, the object gets out of scope and can be GCed.

Ie even if you fix your first problem (by defining a final method in your class that handles the finalization stuff), you'll still need to save the finalizerGuardian in a instance variable.

like image 33
Voo Avatar answered Oct 12 '22 11:10

Voo


Super.finalize() is not getting called because Sub overrides it. Try adding a Super._finalize() method and calling it from Super.finalize() and the finalizer guardian.

Also, I think finalizerGuardian needs to be a field of Super. Otherwise, it can get garbage collected even if the Super object is still strongly reachable.

like image 38
Adam Crume Avatar answered Oct 12 '22 10:10

Adam Crume