skytree
skytree

Reputation: 1100

Test Garbage collection by finalize() function in Java, alive or dead?

As you can see in the first block SAVE_HOOK = null; before going inside the if branch, I think SAVE_HOOK == null, so it should not go into SAVE_HOOK.isAlive();. But actually, I test it in the Eclipse:

Eclipse IDE for Java Developers

Version: Neon.3 Release (4.6.3)

Build id: 20170314-1500

Why does this happen?

public class FinalizeEscapeGC {

    public static FinalizeEscapeGC SAVE_HOOK = null;

    public void isAlive() {
        System.out.println("yes, i am still alive :)");
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize mehtod executed!");
        FinalizeEscapeGC.SAVE_HOOK = this;
    }

    public static void main(String[] args) throws Throwable {
        SAVE_HOOK = new FinalizeEscapeGC();

        // ---------------block 1----------------//
        SAVE_HOOK = null;
        System.gc();
        Thread.sleep(500);
        if (SAVE_HOOK != null) {    // "SAVE_HOOK = null;"
            SAVE_HOOK.isAlive();    //  why the frist time it can go inside this if branch? 
        } else {
            System.out.println("no, i am dead :(");
        }
        // ---------------block 1----------------//

        // the same as the above block
        // ---------------block 2----------------//
        SAVE_HOOK = null;
        System.gc();        
        Thread.sleep(500);
        if (SAVE_HOOK != null) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("no, i am dead :(");
        }
        // ---------------block 2----------------//
    }
}

Result:

finalize mehtod executed!

yes, i am still alive :)

no, i am dead :(

Upvotes: 1

Views: 304

Answers (3)

shmosel
shmosel

Reputation: 50776

It sounds like you're trying to ask two questions:

  1. Why is SAVE_HOOK not null after the first block?
  2. Why is it null after the second, identical block?

The simple answer to the first question is: Because System.gc() triggered the garbage collector, which in turn ran the finalizer, which explicitly reassigns the reference. But I assume you know that already, and what you mean to ask is: Why wasn't the object reclaimed after the finalizer completed?

The answer is in the documentation to finalize():

After the finalize method has been invoked for an object, no further action is taken until the Java virtual machine has again determined that there is no longer any means by which this object can be accessed [...] at which point the object may be discarded.

So as long as you still have a strong reference to the object, it will never be garbage collected.

The answer to the second question is: You set it to null and it's never reassigned because the finalizer for a particular instance will only ever run once. This is also in the documentation, right after the previous quote:

The finalize method is never invoked more than once by a Java virtual machine for any given object.

Upvotes: 1

Gao Peng
Gao Peng

Reputation: 23

In an object's life lifecycle, it will go through reachable->finalizable->finalized->reclaimed phases. After finalize() method was execute, the object will get in finalized phase, and wait for the next gc trigger, it will be reclaimed. So in the lifecycle, the finalize() method will be exectued only once. Your SAVE_HOOK is a static variable and it was assigned value in finalize() method again. That's why in first if block, it's not null. but the second time, it's dead.

Upvotes: 0

Stephen C
Stephen C

Reputation: 719626

It boils down to this: an object can only be finalized once in its lifetime. The finalize method can cause the object to escape deletion the first time, but next time the object is detected as unreachable, it will simply be deleted.

Upvotes: 1

Related Questions