关于GC(二)关于回收算法

2016-06-29  本文已影响170人  Mooner_guo
  1. 引用计数算法
  2. 可达性算法
    2.1 标记清除算法
    2.2 复制算法
    2.3 标记整理算法

一、 引用计数器算法

算法实现简单,效率很高。但是该算法被抛弃,不会用在jvm中清除对象,因为不能解决相互引用的问题。(可以看完下面的然后回过头来看这段话)

算法基本思想:
 给每个对象增加一个引用计数器,有一个引用就+1,一个引用失效时就-1,当引用计数器数字为0时候,这个对象就不可能在被使用,就会被回收。

如果使用这种算法,那么相互引用的情况下无法被GC回收的案例如下:


import org.junit.Test;

public class GcTest {

    class A{
        private B b;

        public void setB(B b) {
            this.b = b;
        }
    }

    class B{
        private A a;

        public void setA(A a) {
            this.a = a;
        }
    }

    @Test
    public void test(){
        A a = new A();
        B b = new B();
        a.setB(b);
        b.setA(a);
        //========
        a = null;
        b = null;
    }
}

显然当a、b置为null时,jvm会GC掉这个对象的。

二、可达性算法

关键字:

算法基本思想:
 引用链是个树形结构,以GC Roots为起点向下搜索,所走过的路径就是引用链,当发现一个对象和GC Roots间没有任何引用链,那么这个对象就是不可用的,应该被GC。
 如图2.1所示,绿色的对象到GC Roots间没有任何引用链,所以都是不可达的,都是不可用对象。

图2.1 GC roots tracing 算法

基于可达性算法,如下是GC的回收对象具体实现的理论算法。

2.1 标记清除算法

比较基础的算法了,见名知意,就是把不可达对象标记起来,然后统一交给GC去回收该对象内存。
问题:
 会造成大量不连续的内存碎片,如果碎片太多的话,如果来个较大的对象,发现无法分配内存就不得不提前触发GC回收内存。

见图知意,如图2.2所示,会收回会发现有很多不连续的内存。

图2.2 标记清除
2.2 复制算法

把内存空间对半分,先紧着一半的内存A用,用完了就触发GC把活着的对象复制到另一半B并清空A,这时候AB内存使用对调。
好处:
分配对象的时候不用考虑碎片等复杂问题,只要移动堆顶指针按顺序分配即可,实现简单,运行高效。

坏处:

变化:spot将内存分为Eden、from suvivor和to suvivor 8:1:1来采用复制算法。(用来处理年轻代对象回收);分配担保机制;

继续看图说话,如图2.3

图2.3 复制算法
2.3 标记-整理算法

老年代特点,解决复制算法的问题。
仍然是标记-清楚算法,但是后续步骤还会让存活对象向一端移动,然后清除掉端边界以外的内存。

图2.4 标记整理
2.4 分代回收算法

spot虚拟机根据存货周期将内存分为年轻代、老年代。
年轻代分为Eden、2个suvivor区。
主要还是采用复制算法。

上一篇 下一篇

猜你喜欢

热点阅读