• jvm回收对象


    jvm在判断对象死亡之前需要判断对象是否可到达,方法有引用计数算法和可达性分析算法,jvm采用的是后者.首先来了解一下这两种算法.

    引用计数算法:

    算法定义

             为每个对象增加一个字段记录被引用的次数,并由运行时跟踪和更新引用的总数;

    object p = new ComparableInt32(57);
     
    object q = p;

    我们实例化了一个对象ComparableInt32,并将其赋值给变量p,此时p引用了该对象,所以其计数器为1;然后我们又用p给变量q赋值,此时q也引用了该变量,所以其计数器变为2;如下图所示

     

     

    从上图我们可以看到,引用类型每次赋值都需要运行时更新计数器,运行时的更新代码可能如下

    if (p != q)
    
    {
    
             if (p != null)
    
                       --p.refCount;
    
             p = q;
    
             if (p != null)
    
                       ++p.refCount;
    
    }

     

    计数器算法的一大优势就是不用等待内存不够用的时候,才进行垃圾的回收,其可以在赋值操作的同时,检查计数器是否为0,如果是的话就可以立即回收;运行时的代码可能如下

    if (p != q)
    
    {
    
             if (p != null)
    
                       if (--p.refCount == 0)
    
                                heap.Release(p);
    
             p = q;
    
             if (p != null)
    
                       ++p.refCount;
    
    }

    计数器算法的一大缺点就是不能解决循环引用的问题;如下图,我们构造了一个列表,我们将最后一个元素的next属性指向第一个元素,即引用第一个元素,从而构成循环引用;这个时候如果我们将列表的头head赋值为null,此时列表的各个元素的计数器都不为0,同时我们也失去了对列表的引用控制,从而导致列表元素不能被回收!

     

     可达性分析算法:

    算法特点

    1.       需要单独的字段存储计数器,增加了存储空间的开销;

    2.       每次赋值都需要更新计数器,增加了时间开销;

    3.       垃圾对象便于辨识,只要计数器为0,就可作为垃圾回收;

    4.       及时回收垃圾,没有延迟性;

    5.       不能解决循环引用的问题;

    在主流的商用程序语言(Java、C#,甚至包括前面提到的古老的Lisp)的主流实现中,都是称通过可达性分析(Reachability Analysis)来判定对象是否存活的。这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的。如图3-1所示,对象object 5、object 6、object 7虽然互相有关联,但是它们到GC Roots是不可达的,所以它们将会被判定为是可回收的对象。

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

    虚拟机栈(栈帧中的本地变量表)中引用的对象。

    方法区中类静态属性引用的对象。

    方法区中常量引用的对象。

    本地方法栈中JNI(即一般说的Native方法)引用的对象。

    在确定对象不可到达之后,该对象并不会立刻被释放,jvm会判断该对象是否有finalize()方法,若有,则开启一个优先级较低的线程去执行这个方法.如果在执行的过程中,该对象又与引用链上的其他对象建立了关联,则该对象便获得重生,不会被释放.否则,在执行之后被jvm释放.

    不过每个对象的finalize()方法仅能执行一次,若一个对象在第一次GC时已经执行了finalize()方法,且获得了重生,则下一次GC时若该对象为不可到达,则直接被释放.(建议:尽量不要使用finalize()方法).

  • 相关阅读:
    数据仓库- 建模理念
    SpringBoot- springboot集成Redis出现报错:No qualifying bean of type 'org.springframework.data.redis.connection.RedisConnectionFactory'
    CDH- cdh kafka已经卸载了,但是服务器还有kafka-topics这些命令可用,导致重新安装kafka出现问题
    【JZOJ6217】【20190614】最大面积
    【JZOJ6216】【20190614】序列计数
    【JZOJ6228】【20190621】ni
    【JZOJ6227】【20190621】ichi
    【JOISC2019|2019】【20190622】cake3
    【JOISC2018|2019】【20190622】mergers
    【JOISC2018|2019】【20190622】minerals
  • 原文地址:https://www.cnblogs.com/vinozly/p/5076875.html
Copyright © 2020-2023  润新知