天天看点

finalize方法

​ finalize()是Object中的方法,当垃圾回收器将要回收对象所占内存时,该方法被调用,即当一个对象被虚拟机宣告死亡时会先调用它的finalize()方法,让此对象临终前交代点遗言,当然对象也可以趁机复活。

死亡判定

引用计数器法

​ 给对象添加一个引用计数器,每当有一个地方引用它,计数器就加1,当引用失效时,计数器就减1,任何时刻当计数器为0的时候,这个对象就不能再被使用了。优点:实现简单效率高。缺点:主流JVM不使用这个算法,因为无法解决对象循环引用的问题。

可达性分析算法

​ 通过一系列称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的。可作为GC root的对象有:方法区中常量引用的对象,方法区中静态属性引用的对象,虚拟机栈中引用的对象,本地方法中引用的对象。

可达性分析算法中,要宣告一个对象真正的死亡,要经历两次标记的过程:

  1. 如果对象在经历可达性分析之后,发现没有与GC root相连的引用链,将会被第一次标记并且进行第一次筛选,筛选的条件是是否有必要执行finalize()方法,当对象没有finalize()方法或者虚拟机已经调用过finalize()方法,视为没有必要执行。
  2. 如果这个对象被判定为有必要执行finalize()方法,那么对象将会放置在一个F-Queue队列中,稍后由一个虚拟机自动建立的、低优先级的Finalizer线程去执行它。finalize()方法是对象逃离死亡的最后一次机会,稍后GC将会对队列进行第二次小规标记,如果对象要finalize()拯救它,只需要与引用链上的任意一个对象建立关联即可,那么第二次标记的时候它将会被移出即将回收的集合,如果没逃脱,就会真正被回收。

最后挣扎

​ 对象被判定死亡以后,还有机会挣扎一下。

​ 重写finalize()方法,将对象重新引用到"GC Roots"链上

不确定性

finalize()只会在对象内存回收前被调用一次,但是不保证里面的方法会被执行完。如果执行比较慢,还没来得及复活,就被杀死回收了。

finalize()的作用

其实,并没有什么乱用。

书中记载,“它不是C/C++中的析构函数,而是Java刚诞生时为了使C/C++程序员更容易接受它所做出的一个妥协”。

代码实现

/**
 * @author Fibonacci
 * @date 2020-12-26 10:24
 */
public class QuoteType {

    @Override
    protected void finalize(){
        System.out.println("GC的时候会执行");
    }

    public static void main(String[] args) {
        // 创建一个对象
        QuoteType quoteType = new QuoteType();
        // 对象设置为null
        quoteType = null;
        // 启用垃圾回收
        System.gc();

        // 阻塞等待垃圾回收完成
        try {
            Thread.sleep(5000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}