标记-清除算法
- 算法分为“标记”和“清除”两个阶段
- 首先标记出所有需要回收的对象,在标记完成后,统一回收掉所有被标记的对象。或者,标记存活的对象,统一回收所有未被标记的对象
- 标记过程就是对象是否属于垃圾的判定过程,主要是可达性分析算法
- 图示如下:
- 缺点:
执行效率不稳定,如果Java堆中包含大量对象,而且其中大部分是需要被回收的,这时必须进行大量标记和清除的动作,导致标记和清除两个过程的执行效率都随对象数量增长而降低;
内存空间的碎片化问题,标记、清除之后会产生大 量不连续的内存碎片,空间碎片太多可能会导致当以后在程序运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
标记复制算法
-
简称为复制算法,为了解决标记-清除算法面对大量可回收对象时执行效率低的问题
-
如果内存中多数对象都是存活的,这种算法将会产生大量的内存间复制的开销,但对于多数对象都是可回收的情况,算法需要复制的就是占少数的存活对象
-
主要用于新生代,因为新生代大多数对象都会在GC后回收,新生代中的对象有98%熬不过第一轮收集
-
HotSpot 的新生代采用复制算法,默认Eden和Survivor的大小比例是8∶1
-
堆空间的分代图,新生代包括Eden和Survivor
-
回收过程如下
幸村区survivor分为两个区域,from和to,且在内存复制的过程中,这两块区域是来回交换的;
如上图,黄色小块表示Minor GC后存活的对象,Eden和from区的存活对象统一复制到to区域,from变为to区,to区变为from区;当Survivor空间不足以容纳一次Minor GC之后存活的对象时,就需要依赖其他内存区域(实 际上大多就是老年代)进行分配担保(Handle Promotion)。 -
缺点:浪费了一半的survivor内存空间
-
思考,为什么不采用一块survivor区?
答:会产生内存碎片。如下图,第一次GC后,1、2、3对象复制到Survivor区;第二次GC,Survivor区的 2 被回收,对象4复制到Survivor,则会产生内存碎片。
标记-整理算法
-
标记-复制算法在对象存活率较高时就要进行较多的复制操作,效率将会降低。
-
标记-整理算法与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内 存。即首先清理再回收,避免产生内存碎片。
-
缺点:如果移动存活对象,尤其是在老年代这种每次回收都有大量对象存活区域,移动存活对象并更新所有引用这些对象的地方将会是一种极为负重的操作,而且这种对象移动操作必须全程暂停用户应用 程序才能进行
-
HotSpot虚拟机里面关注吞吐量的Parallel Scavenge收集器是基于标记-整理算法的,而关注延迟的CMS收集器则是基于标记-清除算法的