Java虚拟机:如何断定哪些对象可回收?

版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习!算法

       在堆内存中存放着Java程序中几乎全部的对象实例,堆内存的容量是有限的,Java虚拟机会对堆内存进行管理,回收已经“死去”的对象(即不可能再被任何途径使用的对象),释放内存。垃圾收集器在对堆内存进行回收前,首先要作的第一件事就是肯定这些对象中哪些还存活着,哪些已经死去。Java虚拟机是如何判断对象是否能够被回收的呢?学习

       引用计数算法spa

       引用计数算法的原理是这样的:给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;在任什么时候刻计数器的值为0的对象就是不可能再被使用的,也就是可被回收的对象。code

       引用计数算法的效率很高,可是主流的JVM并无选用这种算法来断定可回收对象,由于它有一个致命的缺陷,那就是它没法解决对象之间相互循环引用的的问题,对于循环引用的对象它没法进行回收。对象

       假设有这样一段代码:blog

       

public class Object {
    
    public Object instance;
    
    public static void main(String[] args) {
        
        // 1
        Object objectA = new Object();
        Object objectB = new Object();
        
        // 2
        objectA.instance = objectB;
        objectB.instance = objectA;
        
        // 3
        objectA = null;
        objectB = null;
        
    }

       程序启动后,objectA和objectB两个对象被建立并在堆中分配内存,这两个对象都相互持有对方的引用,除此以外,这两个对象再无任何其余引用,实际上这两个对象已经不可能再被访问(引用被置空,没法访问),可是它们由于相互引用着对方,致使它们的引用计数器都不为0,因而引用计数算法没法通知GC收集器回收它们。内存

       实际上,当第1步执行时,两个对象的引用计数器值都为1;当第2步执行时,两个对象的引用计数器都为2;当第3步执行时,两者都清为空值,引用计数器值都变为1。根据引用计数算法的思想,值不为0的对象被认为是存活的,不会被回收;而事实上这两个对象已经不可能再被访问了,应该被回收。虚拟机

       可达性分析算法class

       在主流的JVM实现中,都是经过可达性分析算法来断定对象是否存活的。可达性分析算法的基本思想是:经过一系列被称为"GC Roots"的对象做为起始点,从这些节点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots对象没有任何引用链相连,就认为GC Roots到这个对象是不可达的,断定此对象为不可用对象,能够被回收。效率

       

       在上图中,objectA、objectB、objectC是可达的,不会被回收;objectD、objectE虽然有关联,可是它们到GC Roots是不可达的,因此它们将会被断定为是可回收的对象。

       在Java中,可做为GC Roots的对象包括下面几种:

       一、虚拟机栈中引用的对象;

       二、方法区中类静态属性引用的对象;

       三、方法区中常量引用的对象;

       四、本地方法栈中Native方法引用的对象。

       以上探讨了断定对象是否可回收的两种算法,断定对象是否可回收只是垃圾回收的第一步,接下来还要解决什么时候回收以及如何回收的问题,在后面的文章中咱们来探讨这些问题。

相关文章
相关标签/搜索