您现在的位置:首页 > >

标记、清除算法是如何处理循环引用?

发布时间:

目前的GC算法有两个大分类:引用计数可达性。下面来说说引用计数法是如何统计所有对象的引用计数的,再对比分析可达性算法是如何解决引用技术算法的不足,好比说循环引用。


循环引用
举个栗子:有两个对象,A引用B,B引用A。
这种情况下两个对象都存在引用,那么是否这两个对象就无法被GC了呢?先卖个关子,让我们记住这种情况,带着疑问往下读,接下来了解一下GC算法的一些概念。


GC采用的算法
1.引用计数算法:每个对象都有一个引用计数器,当对象被引用时计数器+1,对象引用失效的时候,引用计数器-1,当计数为0的时候,意味着此对象是一个垃圾对象,可以被gc了。


2.可达性算法:从GC Roots作为起点开始搜索,对于GC Roots无法到达的对象便成了垃圾回收对象,随时可被gc掉。常见的可达性算法有标记、清除法。


对这两种算法有一定的了解之后,我们来观看下面这两个图(以下图片均来自知乎):


引用计数法

(图一)
这里有四个step:
? step1:Java堆中实例1引用计数+1,当前计数为1;
? step2:Java堆中实例2引用计数+1,当前计数为1;
? step3:Java堆中实例2引用计数+1,当前计数为2;
? step4:Java堆中实例1引用计数+1,当前计数为2。


四个步骤下来,堆中实例1计数=堆中实例2计数=2。


接下来再看一图:

(图二)
我们看到step1跟step2的连线已经消失了。也就是栈帧中的obj1跟obj2不再指向Java堆中的实例了。我们拆分成两个步骤(step5、step6),这时:


? step5:obj1不再指向实例1,引用数-1,当前计数为2-1=1;
? step6:obj2不再指向实例1,引用数-1,当前计数为2-1=1。


我们发现,实例1和实例2的计数都不为0,如果采用引用计数法的话,那么这两个实例所占用的内存就得不到释放了。所以,引用计数法无法解决循环利用
的gc问题。


那么,可达性算法就可以吗?它是如何操作的?


上面提到的可达性算法的概念,有个字眼-GC Roots


可以作为GC Roots的对象
? 虚拟机栈的栈帧的局部变量表所引用的对象;
? 本地方法栈的JNI所引用的对象;
? 方法区的静态变量和常量所引用的对象.


图二中,把虚拟机栈的栈帧的局部变量表看作GC Roots的话,Java堆中的实例1跟实例2就与GC Roots“失联”了。GC Roots无法到达的对象便成了垃圾回收对象,随时被gc掉。所以,可达性算法可以处理循环引用的问题,解决了引用计数算法带来的缺陷。这也是目前虚拟机基本都是采用可达性算法的原因。


大家有技术上的兴趣请加Q群:543827083。我们一起聊聊Android开发的知识


热文推荐
猜你喜欢
友情链接: 大学学习资料 人文社科 经营营销资料 工程资料大全 IT文档 自然科学