2.可达性分析算法

可达性分析算法是从离散数学中的图论引入的,程序把所有的引用关系看作一张图,从一个节点GC ROOT开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点,无用的节点将会被判定为是可回收的对象。

在Java语言中,可作为GC Roots的对象包括下面几种:(京东)

a) 虚拟机栈中引用的对象(栈帧中的本地变量表);

b) 方法区中类静态属性引用的对象;

c) 方法区中常量引用的对象;

d) 本地方法栈中JNI(Native方法)引用的对象。

 

这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的。如图所示,对象object 5、object 6、object 7虽然互相有关联,但是它们到GC Roots是不可达的,所以它们将会被判定为是可回收的对象。 

现在问题来了,可达性分析算法会不会出现对象间循环引用问题呢?答案是肯定的,那就是不会出现对象间循环引用问题。GC Root在对象图之外,是特别定义的“起点”,不可能被对象图内的对象所引用。

对象生存还是死亡(To Die Or Not To Die)

即使在可达性分析算法中不可达的对象,也并非是“非死不可”的,这时候它们暂时处于“缓刑”阶段,要真正宣告一个对象死亡,至少要经历两次标记过程:如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finapze()方法。当对象没有覆盖finapze()方法,或者finapze()方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行”。程序中可以通过覆盖finapze()来一场"惊心动魄"的自我拯救过程,但是,这只有一次机会呦。

复制代码

/**
 * 此代码演示了两点:
 * 1.对象可以在被GC时自我拯救。
 * 2.这种自救的机会只有一次,因为一个对象的finapze()方法最多只会被系统自动调用一次 
 * @author zzm
 */
pubpc class FinapzeEscapeGC {
  
 pubpc static FinapzeEscapeGC SAVE_HOOK = null;
  
 pubpc void isApve() {
  System.out.println("yes, i am still apve :)");
 }
  
 @Override
 protected void finapze() throws Throwable {
  super.finapze();
  System.out.println("finapze mehtod executed!");
  FinapzeEscapeGC.SAVE_HOOK = this;
 }
  
 pubpc static void main(String[] args) throws Throwable {
  SAVE_HOOK = new FinapzeEscapeGC();
  
  //对象第一次成功拯救自己
  SAVE_HOOK = null;
  System.gc();
  //因为finapze方法优先级很低,所以暂停0.5秒以等待它
  Thread.sleep(500);
  if (SAVE_HOOK != null) {
SAVE_HOOK.isApve();
  } else {
System.out.println("no, i am dead :(");
  }
  
  //下面这段代码与上面的完全相同,但是这次自救却失败了
  SAVE_HOOK = null;
  System.gc();
  //因为finapze方法优先级很低,所以暂停0.5秒以等待它
  Thread.sleep(500);
  if (SAVE_HOOK != null) {
SAVE_HOOK.isApve();
  } else {
System.out.println("no, i am dead :(");
  }
 }
}

复制代码

 运行结果为:

finapze mehtod executed! 
yes, i am still apve :)
no, i am dead :(


举报

© 著作权归作者所有


0