JVM 中判断对象是否 “存活” 的算法 —— 可达性分析算法

在堆中,几乎存放着所有的对象实例,那么回收这些对象实例时,我们需要判断哪些对象是 “已死” 可以回收的,哪些对象是 “存活” 不需要回收的,下面就来介绍一下 JVM 中如何判断上述问题的。

基本思路

通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。
这里写图片描述

哪些可以作为GC Roots

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象。
  • 方法区中类静态属性引用的对象。
  • 方法区中常量引用的对象。
  • 本地方法栈中JNI(即一般说的Native方法)引用的对象。

对象自我拯救

注意,当一个对象实例被标记为不可达对象时,并不是一定会被回收,只是将该对象添加到回收的列表中。
那当被添加到回收列表中时,如果将自身从该列表移除呢?也就是说将该对象重新变成有用的对象呢?
Java Object类提供了一个对象自我救赎的方法:

protected void finalize();//当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。

如果对象要在 finalize() 中成功拯救自己——只要重新与引用链上的任何一个对象建立关联即可,譬如把自己(this关键字)赋值给某个类变量或者对象的成员变量。
但是注意,finalize()方法只会被调用一次!
我们来看一下下面的例子:

/**
 * 此代码演示了两点: 
 * 1.对象可以在被GC时自我拯救。 
 * 2.这种自救的机会只有一次,因为一个对象的finalize()方法最多只会被系统自动调用一次
 */
public class FinalizeEscapeGC {
    public static FinalizeEscapeGC SAVE_HOOK = null;

    public void isAlive() {
        System.out.println("yes,i am still alive :)");
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize mehtod executed!");
        FinalizeEscapeGC.SAVE_HOOK = this;
    }

    public static void main(String[] args) throws Throwable {
        SAVE_HOOK = new FinalizeEscapeGC();
        // 对象第一次成功拯救自己
        SAVE_HOOK = null;
        System.gc();
        // 因为finalize方法优先级很低,所以暂停0.5秒以等待它
        Thread.sleep(500);
        if (null != SAVE_HOOK) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("no,i am dead :(");
        }
        // 下面这段代码与上面的完全相同,但是这次自救却失败了
        SAVE_HOOK = null;
        System.gc();
        // 因为finalize方法优先级很低,所以暂停0.5秒以等待它
        Thread.sleep(500);
        if (null != SAVE_HOOK) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("no,i am dead :(");
        }
    }
}

运行结果如下:

finalize mehtod executedyes,i am still alive :)
no,i am dead :(

本文的内容、图片和代码参考自:《深入理解Java虚拟机:JVM高级特性与最佳实践》

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Lin_wj1995/article/details/79970362
文章标签: JVM
个人分类: JVM
所属专栏: JVM介绍
上一篇JVM运行时数据区域 —— 程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区、运行时常量池
下一篇JVM垃圾回收集算法 —— 标记-清除算法、复制算法、标记-整理算法
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭