可达性分析算法与理解误区

摘引《深入理解JVM》:

在主流的商用程序语言中(Java和C#),都是使用可达性分析算法判断对象是否存活的。这个算法的基本思路就是通过一系列名为GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的,下图对象object5, object6, object7虽然有互相判断,但它们到GC Roots是不可达的,所以它们将会判定为是可回收对象。此处我的理解可能与之正好相反,首先我们是能找虚拟机栈中的对象引用,也就是GC roots,通过它,我们能找到堆中被引用的对象,我们给他标记一次,然后顺着字段引用不断往下找,路径上的都标记一下。全部标记完成后,违背标记的就是不可达对象,进行回收。

那么那些点可以作为GC Roots呢?一般来说,如下情况的对象可以作为GC Roots:

  1. 虚拟机栈(栈桢中的本地变量表)中的引用的对象
  2. 方法区中的类静态属性引用的对象
  3. 方法区中的常量引用的对象
  4. 本地方法栈中JNI(Native方法)的引用的对象

此处我的理解可能与之正好相反,首先我们是能找虚拟机栈中的对象引用,也就是GC roots,通过它,我们能找到堆中被引用的对象,我们给他标记一次,然后顺着字段引用不断往下找,路径上的都标记一下。全部标记完成后,违背标记的就是不可达对象,进行回收。

首先来看一个简单的例子:

其中i字段用来标识是哪个Test对象;

public class Test {
    public Test instance;
    public int i;
    public Test(int i){
        this.i=i;
    }
}
public static void main(String[] args) {
    Test test=new Test(0);
    Test test1=new Test(1);
    Test test2=new Test(2);
    test.instance=test1;
    test1=test2;
    System.out.println(test.instance.i);
}

简单猜测一下输出结果是什么。

 

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

输出结果是1;

没毛病!

但是这看起来好像是与上面的图有矛盾啊,为什么test1已经指向了test2,那照理说test.instance也应该指向test2才对啊

否则上面图又应该怎么解释呢。

其实这种想法是错误的

引用变量只能是指向某个对象的,而不能是指向引用的。

为什么这样?

考虑虚拟机栈,里面存着本地变量表,里面存着某个引用,此引用是指向java堆中的某个对象,,所有对引用的修改都将会直接转变成对原对象的修改,而反之如果是使用某原引用指向堆中对象,其他引用再指向该引用,那么当运行时就会发生多次寻址,使得程序运行效率是极不稳定,而且也容易出现循环引用的现象。这也是为什么引用计数法不被看好的原因

既然如此,为什么为什么上面的那个图是有多层构成呢?

首先 是object1有多个字段, 该字段指向多个对象,然后字段指向的对象中又包含多个字段,这些字段又指向多个对象,如此递归下去。

注意是字段,而非运行时的变量。

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值