jvm---2、GC收集算法

GC收集器算法:
1、标记--清除算法
2、复制算法
3、标记--整理

4、分代收集算法

写在前面:对象存活算法:
GC 收集器对不再使用(死亡)的对象进行内存回收,那么就要判定一个对象是否存活。
对象存活算法通过对象可达性分析来判定对象是是否存活的。基本思路是:通过一系列称为“GC Roots”对象作为起点,当一个对象到GC Roots 不可达时,证明对象是不可用的(没有外部对象的引用了,如循环引用)。
如下图:A B C D 是可用的, X  Y 虽然相互引用,但是是不可达GC Roots 的所以是不可用的(可以回收的对象)。
jvm---2、GC收集算法

GC Root 对象包括下面几种对象:
1、虚拟机栈中的引用对象
2、方法区中类静态属性引用的对象
3、方法区中常量引用对象
4、本地方法栈中JIN(即Native 方法)引用对象

标记--清除算法
算法分为“标记”、“清除”两个阶段,第一个阶段就是标记出“已死亡”对象,第二个阶段把所有已标记的“死亡对象”统一回收。
此算法是最基本的算法,后面的算法都是基于这种思路并对不足的地方进行改进的。
缺点:
1、效率不高

2、标记清除后会产生大量的空间碎片

          jvm---2、GC收集算法


复制算法
解决“标记--清除”算法的效率问题。将内存分为大小相等的两块,每次只使用其中的一块。当这一块内存用完了,就将还存活的对象复制到另一块,然后再把不再使用的对象内存一次清理掉。
优点:这样每次都对整个内存的一半区域进行回收,内存分配的时候也不用考虑内存碎片问题,只要移动堆顶指针顺序分配内存就可以,简单高效。
缺点:1、内存只使用了一半,如果不想浪费50%的内存就要有分配担保。2、如果对象存活率高就要进行较多的复制操作

        jvm---2、GC收集算法

现在商业虚拟机都是用“复制算法”来回收新生代的。
新生代分为一个Eden 区和两个 Survivor 区域,每次使用Eden 区和一个 Survivor 区,这样只有一个 Survivor 被浪费。
创建对象时先分配在Eden区,当Eden 区放不下对象时,会产生一次Minor GC,把Eden存活的对象放到 Survivor from 区(如果放不下怎么搞?),把“死亡对象”清除。再在Eden区分配对象,当下一次Minor GC 时,就会把Eden 区存活对象和Survivor from 区的存活对象一起放到Survivor to 区。再下一次Minor GC时,Survivor to 中对象就放到老年代了。
如果Survivor 区不够了,就要依赖其它内存块,这时用到老年代进行分配担保(GC收集器执行规则会涉及到)。


标记--整理
复制算法不适用对象存活率高的情况,也就是不适用“老年代”。
根据“老年代”对象特点(存活时间比较长,可能几个Full GC 都没有回收),“标记--整理”算法产生。
“标记--整理”算法的标记过程和“标记--清除”算法一样,“标记--整理”是对标存活的记对象的向一端移动,然后直接清理掉边界以外的内存,而“标记--清理”是清理掉“死亡”对象。
这样就不会产生内存碎片。

jvm---2、GC收集算法

分代收集算法
当前GC收集都采用“分代收集”算法,就是根据对象的存活周期不同把堆分成几块,一般是把堆分成“新生代”、“老年代”,再根据“新生代”、“老年代”的不同特点分别采用不同的GC收集算法。
“新生代” 存活率代,并且有“老年代”分配担保,所以采用“复制算法”,复制少量的对象就可以快速实现垃圾清理,并且不会产生内存碎片。
“老年代” 存活率高,没有额外的内存进行分配担保,采用“标记--清理”或者“标记--整理”回收内存。

注:具体的算法实现也不是这么绝对,可能是进行几次“标记--清理”后回收后,进行一次“标记--整理”消除内存碎片。