56.对象的finalization机制、finalize方法理解

 

1.对象的finalization机制

  1. Java提供了finalization机制来允许开发人员提供对象销毁之前自定义处理逻辑。
  2. 垃圾回收一个对象之前,总会先调用这个对象的finalize()方法
  3. finalize()方法是Object类中定义的,允许在任何子类中被重写,用于对象被回收时进行资源释放,例如,关闭数据库连接等等。
    在这里插入图片描述
  4. 不要主动的调用finalize()方法,应该交给垃圾回收机制来调用。
    原因:
    a)finalize()可能导致对象复活
    b)finalize()执行时间没有保障,完全有GC线程决定,极端情况下,若不发生GCfinalize()就不会被调用
    c)糟糕的finalize()会影响GC的性能
    在这里插入图片描述
  5. JVM中的对象可能出现的3种状态。
    a)可触及的:从根节点开始,可以到达这个对象
    b)可复活的:对象的所有引用都被释放,但是对象可能在finalize()被复活(例如:在finalize()中又有新的引用指向该对象)。
    c)不可触及的,对象的finalize()被调用之后,对象没有复活,那么会进入不可触及的状态。不可触及的对象不可能被复活,因为finalize()只会调用一次

只有不可触及的对象才能够被回收。
在这里插入图片描述
判断一个对象是否可以被回收:

    1. 如果objAGC Roots没有引用链,则进行第一次标记。(这里的标记意思是,对象是不可达的,对象可能是可复活的或者不可触及的。)
    2. 进行筛选,判断对象是否需要执行finalize()方法
      1)如果对象objA没有重写finalize()方法,或者finalize()方法已经被虚拟机调用过,则虚拟机认为“没有必要执行finalize()”,objA被判定为不可触及的
      2)如果objA重写了finalize()方法,且还未执行过,那么objA会被插入到F-Queue队列中,由一个虚拟机自动创建的、低优先级的Finalizer线程触发其finalize()方法。
      3) finalize()方法是对象逃脱死亡的最后机会,稍后GC会对F-Queue中的objA对象进行第二次标记,如果objAfinalize()方法中与引用链上的任何一个对象建立了联系(也就是复活了),那么第二次标记时,objA会被移出“即将回收”集合。之后,对象会再次出现没有引用存在的情况,在这个情况下,finalize()方法不会被再次调用,对象会直接变成不可触及状态。因为,一个对象的finalize()方法只会被调用一次。
      在这里插入图片描述
      演示对象的finalization机制的例子:
      /**
       * 测试Object类中finalize()方法,即对象的finalization机制。
       */
      public class CanReliveObj {
          public static CanReliveObj obj;//类变量,属于 GC Root
      
      
          //finalize方法只能被调用一次
          @Override
          protected void finalize() throws Throwable {
              super.finalize();
              System.out.println("调用当前类重写的finalize()方法");
              obj = this;//当前待回收的对象在finalize()方法中与引用链上的一个对象obj建立了联系。 obj是GC Roots,this是当前对象,也就是要被回收的对象。
          }
      
      
          public static void main(String[] args) {
              try {
                  obj = new CanReliveObj();
                  // 对象第一次成功拯救自己
                  obj = null;
                  System.gc();//调用垃圾回收器。第一次GC的时候,会执行finalize方法,在finalize方法中,由于obj指向了this,obj变量是一个GC Root,要被回收的对象与引用链上的对象建立了又联系,所以对象被复活了
                  System.out.println("第1次 gc");
                  // 因为Finalizer线程优先级很低,暂停2秒,以等待它
                  Thread.sleep(2000);
                  if (obj == null) {
                      System.out.println("obj is dead");
                  } else {
                      System.out.println("obj is still alive"); // 这句会输出
                  }
                  System.out.println("第2次 gc");
                  // 下面这段代码与上面的完全相同,但是这次自救却失败了
                  obj = null;
                  System.gc(); // 第二次调用GC,由于finalize只能被调用一次,所以对象会直接被回收
                  // 因为Finalizer线程优先级很低,暂停2秒,以等待它
                  Thread.sleep(2000);
                  if (obj == null) {
                      System.out.println("obj is dead"); // 这句会输出
                  } else {
                      System.out.println("obj is still alive");
                  }
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
      }

       

posted @ 2020-11-18 22:41  跃小云  阅读(215)  评论(0编辑  收藏  举报