JVM系列——垃圾收集(二)

2019-08-20  本文已影响0人  阿斯巴甜不太甜

垃圾收集算法

1. 标记—清除算法

标记—清除算法就和其名字一样,分为标记和清除两个阶段:首先按上一篇文章中提到的标记方法对可回收对象进行标记,接着在标记完成后统一回收所有被标记的对象,过程如下:

image

图中的上半部分是回收前的内存状态,下半部分是回收后的状态。由图中我们也可以看出,这个算法思想很简单,但是会产生大量不连续的内存碎片,而一旦空间碎片太多很可能导致以后再程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

另外,这个算法再标记和清除的两个过程中效率都不高。

2. 复制算法

复制算法解决了标记—清除算法中存在的内存不连续问题,他将可用的内存容量划分为大小相等的两块,每次只使用其中的一块,当这一块中没有连续足够的内存供新的对象使用时,就会把当前这一块的对象按顺序复制到另一块内存上。


image

这个算法实现简单,运行高效,但是代价是将原来可用的内存缩小到了原来的一半。

现在的商业虚拟机都采用这种收集算法来回收新生代。IBM公司的专门研究表明,新生代中的对象98%生命周期都很短暂,因此并不需要按照1:1来划分空间,而是将空间按照8:1:1划分为三份,每次使用8+1来进行存储。当回收时把8+1全部复制到另外一个“1”上。当然,我们没有办法保证每次回收只有不多于10%的对象存活,当“1”不够时,需要依赖其他内存(老年代)进行分配担保。

关于新生代、老年代和永久代的概念

3. 标记—整理算法

老年代中的对象不同于新生代,具有长期存活的特点,因此如果存活率高达90%以上,采用复制算法就很棘手了。

根据老年代的特点,有人提出了这种算法,标记过程不变,但后续步骤是让所有存活的对象都向一端移动。


image

4. 分代收集算法

“分代收集”算法,把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记-清理”或“标记-整理”算法来进行回收。

上一篇下一篇

猜你喜欢

热点阅读