谁才是真正的垃圾:判断对象的可触及性

垃圾回收的基本思想是考察每个对象的可触及性,即从根节点开始是否能够访问到这个对象,若是能够,则说明当前对象正在被使用,若是从全部的根节点都没法访问到某个对象,说明该对象已经再也不使用了,通常来讲,此对象符合垃圾回收的条件。可是,一个没法触及的对象有可能在某个条件下复活本身,若是这样,那么对它的回收就是不合理的,为此,须要给出一个可触及性状态的定义,并规定在什么状态下,才能够安全的回收对象。安全

可触及的包括3种状态:jvm

  • 可触及的:从根节点开始,能够到达这个对象;
  • 可复活的:对象的全部引用都被释放,可是对象有可能在finalize()函数中复活;
  • 不可触及的:对象的finalize()函数被调用,而且没有复活,那么就会进入不可触及状态,不可触及的对象不可能被复活,由于finalize()函数只会被调用一次。

以上3种状态,只有在对象不可触及时才能够被回收。ide

1 对象的复活函数

实例1 :前面提到,对象可能在finalize()函数中复活本身,这里给出一个实例。this

package com.jvm;
public class CanReliveObj {
  public static CanReliveObj obj ;
  @Override
  protected void finalize() throws Throwable {
    super.finalize();
    System.out.println("CanReliveObj finalize called");
    obj = this;
  }
  @Override
  public String toString() {
    return "CanReliveObj";
  }

  public static void main(String[] args) throws InterruptedException {
    obj = new CanReliveObj();
    obj = null;
    System.gc();
    Thread.sleep(1000);
    if(obj==null){
      System.out.println("obj is null");
    }else{
      System.out.println("obj 可用");
    }
    System.out.println("第二次GC");
    obj = null;
    System.gc();
    Thread.sleep(1000);
    if(obj==null){
      System.out.println("obj is null");
    }else{
      System.out.println("obj 可用");
    }
  }
}对象

运行代码打印:资源

CanReliveObj finalize called
obj 可用
第二次GC
obj is nullio

能够看出,在第一次将obj置为null后,进行GC,结果发现obj对象被复活了。等到第二次再释放对象引用并运行GC,对象才真正被回收。这是由于第一次GC时,在finalize()函数调用以前,虽然系统中的引用已经被清除,可是在实例方法finalize()中,对象的引用this依然被传入方法内部,致使引用外泄,对象复活,此时对象又变成可触及状态。因为finalize()函数只会被调用一次,所以,在第二次清除释放对象的引用时,对象就再无机会复活,所以会被回收。class

注意:垃圾回收

finalize()函数是一个糟糕的应用模式,不推荐使用finalize()函数释放资源。

由于:其一,finalize()函数有可能发生引用外泄,在无心间复活对象

        其二,因为finalize()是被系统调用的,调用时间是不明确的,所以不是一个好的资源释放方案,推荐使用try-catch-finally语句进行资源的释放。

相关文章
相关标签/搜索