Java 对象是否GC回收

一、对象何时回收

  Java中,使用可达性分析算法标识对象是否回收,即使对象通过可达分析算法被标记为不可达对象,对象不一定被被回收,对象需要经过两次标记才会被回收。在第一次标记后对象会被放入“即将回收”的集合中。对象在随后的判定是否有必要执行finalize()函数后,才会被进行第二次标记,这样,对象才会被回收。

  第一次标记:

  通过可达性分析算法标记对象不可达,第一次被标记,但是,此时对象并不是一定被回收。处于缓刑阶段。

  第二次标记:

  对象第一次标记后,随后进行一次筛选,筛选条件是此对象有必要执行finalize()函数。

  1. 如果,对象没有覆盖finalize()函数,或者对象的finalize()函数已经被虚拟机调用过,那么,虚拟机将视这两种情况为“finalize()函数没有必要执行”。

  2. 如果,对象被判定有必要执行finalize()函数,那么,此对象会被增加到“F-Queue”队列中,F-Queue队列是由虚拟机自动创建的、低优化级的Finalizer线程去执行F-Queue队列中对象的finalize()函数。

  随后GC对F-Queue队列的对象进行第二标记小规模的标记。

  需要注意,这里的“执行”是指虚拟机开始运行对象的finalize()函数,但并不承诺一定等到finalzie()函数运行结束。这样设计的原因,是对象的finalize()函数如果执行耗时操作或者finalize()函数执行进入死循环,会堵塞Finalizer()线程,会导致虚拟机回收子系统崩溃。

二、通过finalize()函数拯救被标记回收对象

  对象回收需要进行两次标记,在第二次标记后才会被回收,第一次标记是通过可达性分析算法完成,随后判定是否有必要执行finalize()函数后进行第二次标记,如果,对象有必要执行finalnze()函数,虚拟机会调用执行对象的finalize()函数。

  通过finalize()函数进行自救需要满足的条件:

  1. 对象需要覆盖finalize()函数。

  2. 对象的finalize()函数没有被虚拟机调用执行过。

  示例:

 

package example;

public class GCTest {
    public static GCTest TEST_HOOK = null;

    public void isLive() {
        System.out.println("Test, GC test object is live.");
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("Test, GC test object is finalize.");
        TEST_HOOK = this;
    }
}


public class Main {

    public static void main(String[] args) {

        GCTest.TEST_HOOK = new GCTest();

        // 第一次自救
        GCTest.TEST_HOOK = null;
        System.gc();
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (GCTest.TEST_HOOK != null) {
            GCTest.TEST_HOOK.isLive();
        } else {
            System.out.println("Test, no, GCTest object is dead.");
        }

        GCTest.TEST_HOOK = null;
        System.gc();
        if (GCTest.TEST_HOOK != null) {
            GCTest.TEST_HOOK.isLive();
        } else {
            System.out.println("Test, no, GCTest object is died.");
        }
    }

}

  结果:

Test, GC test object is finalize.
Test, GC test object is live.
Test, no, GCTest object is died.

Process finished with exit code 0

  第一次将变量赋值为null时,通知gc回收,会虚拟机会调用执行对象的finalize()函数,在函数中可以尝试自救,在第二次赋值null后,再次通知gc,虚拟机不会再调用对象finalize()函数,对象标记回收。对象的finalize()函数虚拟机只会调用执行一次。

 

posted @ 2021-10-18 16:29  naray  阅读(316)  评论(0编辑  收藏  举报