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

标签: JVM
4人阅读 评论(0) 收藏 举报
分类:

在堆中,几乎存放着所有的对象实例,那么回收这些对象实例时,我们需要判断哪些对象是 “已死” 可以回收的,哪些对象是 “存活” 不需要回收的,下面就来介绍一下 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高级特性与最佳实践》

查看评论

深入理解JVM03--判断对象是否存活(引用计数算法、可达性分析算法,最终判定),Eclipse设置GC日志输出,引用

堆中几乎存放着Java世界中所有的对象实例,垃圾收集器在对堆回收之前,第一件事情就是要确定这些对象哪些还“存活”着,哪些对象已经“死去”(即不可能再被任何途径使用的对象) 1、引用计数算法(Refer...
  • oChangWen
  • oChangWen
  • 2016-05-14 17:56:06
  • 7428

javaVM 判断对象实例何时回收 用的可达性分析算法,而非引用计数算法

java虚拟机判断一个对象实例是否可以被回收,并非引用计数算法。因为引用计数算法很难解决对象直接互相循环引用的问题。 所以java C#都是使用可达性分析来判断对象是否可以回收的。...
  • tiantiandjava
  • tiantiandjava
  • 2015-01-30 18:17:35
  • 3121

确定那些对象是垃圾-可达性分析算法

概述 引用计数法 可达性分析算法 概述 程序运行时,堆内存中存在很多的对象,在GC之前需要知道哪些对象能够进行GC,哪些对象不能够精心GC。 引用计数...
  • jtracydy
  • jtracydy
  • 2017-03-11 14:19:00
  • 1134

Java虚拟机垃圾回收(一) 基础:回收哪些内存/对象 引用计数算法 可达性分析算法 finalize()方法 HotSpot实现分析

下面先来了解Java虚拟机垃圾回收的基础内容:如何判断对象是存活还是已经死亡? 介绍相关的垃圾回收基础算法:引用计数算法、可达性分析算法,以及说明finalize()方法作用,最后再来说说HotSpo...
  • tjiyu
  • tjiyu
  • 2017-01-02 22:13:45
  • 4693

java jvm GC的基石 可达性算法

在jvm中 任何堆中对象 与GC root set不可达就会被gc回收。 那么gc root set是什么呢? 1.虚拟机栈(栈帧中的本地变量表)中引用的对象。 2.方法区中类静态属性引用的对象...
  • u011188904
  • u011188904
  • 2016-08-26 11:59:55
  • 735

JVM之判断一个对象是否存活

真正要宣告一个对象死亡,至少要经历两次标记:         1、  如果对象在进行可达性分析后发现没有与GC Root相连接的引用链,将会被第一次标记,并且进行一次筛选,筛选条件是对象是否有必...
  • qlxiaomage
  • qlxiaomage
  • 2014-12-19 21:30:10
  • 617

读书笔记-2java虚拟机的可达性算法与finalize方法

JAVA通过可达性分析算法来确定堆中哪些对象是应该被回收的。 很多人包括我以前在不了解的时候总以为是通过引用计数器来判断某个对象是否应该被回收但是后来想了想包括查阅一些资料发现不是这样的,因为如...
  • u010708203
  • u010708203
  • 2015-07-21 08:39:23
  • 1625

JVM中判断对象是否存活的方法

Java中几乎所有的对象实例都存放在堆中,在垃圾收集器对堆内存进行回收前,第一件事情就是要确定哪些对象还“存活”,哪些对象已经“死去”(即不可能再通过任何途径被使用)。引用计数算法  首先需要声明,至...
  • xiangwanpeng
  • xiangwanpeng
  • 2016-10-24 15:51:16
  • 1102

JVM如何判断对象"死"和"活"

堆中存放着几乎所有的
  • yyywyr
  • yyywyr
  • 2014-09-15 23:55:40
  • 2132

java垃圾回收机制--可达性算法

下面我从一段代码来分析整个过程,并结合模型图来简易讲解,希望能让大家对彻底明白。 在正式回答这个问题之前,先简单说说 Java运行时内存区,划分为线程私有区和线程共享区: (1)线程私有区...
  • LAMP_zy
  • LAMP_zy
  • 2016-11-18 09:56:25
  • 1490
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 1万+
    积分: 615
    排名: 8万+
    博客专栏
    最新评论