垃圾收集算法

来源:互联网 发布:什么抢购软件好 编辑:程序博客网 时间:2024/05/19 18:44

标记-清除(Mark-Sweep)算法

最基础的算法,分为标记和清除两部分:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象,之所以说最基础,是因为后续的收集算法都是基于这种思路对其不足进行改进。

不足有两个:一个是效率问题,标记和清除两个过程的效率都不高;另一个是空间问题,标记清除后会产生大量的不连续的内存碎片,碎片太多可能会导致以后分配较大的对象时,无法找到足够的连续内存而不得不提前出发另一次垃圾收集动作。

这里写图片描述

复制(Copying)算法

将可用内存划分为大小相等的两块,每次只使用其中的一块。一块的内存用完了,就将还存活着的对象复制到另一块去,然后再把已经使用过的内存空间一次清理掉。

好处是每次都是对整个半区进行内存回收,内存分配时不用考虑内存碎片等情况,实现简单,运行高效。代价是将内存缩小为了原来的一半,未免太高了一点。

这里写图片描述

现在的商业虚拟机都采用这种收集算法来回收新生代,但不是1:1的,因为98%的对象都是“朝生夕死”的,而是把内存分为一个较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor空间。HotSpot虚拟机默认Eden和Survivor大小比例为8:1,也就是每次新生代中可用内存空间为整个新生代容量的90%,当然,无法保证每次回收都只有不多于10%的内存存活,若超过这个阈值,就需要依赖其他内存(老年代)进行分配担保(Handle Promotion)

 标记-整理(Mark-Compact)算法

根据老年代的存活对象比较多和没有额外的空间进行担保的特点,提出看标记-整理算法,标记与之前一样,但后续不是直接对可回收对象清理,而是让所有存活的对象向一端移动,然后直接清理掉端边界以外的内存。
这里写图片描述

分代收集(Generation Collection)算法

当前都采用此算法,其只是根据对象的存活周期将内存划分为几块,一般是把Java堆划分为新生代和老年代,这样可以根据各个年代的特点采用最适合的收集算法。

在新生代中,每次垃圾收集有大批对象死去,只有少量存活,所以采用复制算法,只需要付出少量存活对象的复制成本就能完成收集。
老年代中对象存活率高,没有额外的空间担保,就必须采用标记-清理或者标记-整理算法回收。