从如何判定对象消亡的角度触发,垃圾收集算法可以划分为俩类
- 引用计数式垃圾收集
- 追踪式垃圾收集
以下都是追踪式垃圾收集
1.分代收集理论
俩个分代假说:
- 弱分代假说:绝大多数对象都是朝生夕灭的
- 强分代假说:熬过越多次垃圾收集过程的对象就越难以消亡
垃圾收集器的一致的设计原则:收集器应该将java堆划分出不同的区域,然后将回收对象依据其年龄(年龄就是对象熬过垃圾收集过程的次数)分配到不同的区域储存
2.标记-清除算法
俩个阶段,首先标记出所有需要回收的对象,在标记完成后,统一回收掉所有被标记的对象
也可以反过来,标记存活的对象,统一回收未被标记的对象
标记的过程就是对象是否属于垃圾的判定过程
缺点:
- 执行效率不稳定,java堆中如果包含大量对象,而且其中大部分是需要回收的,这时就需要进行大量的标记和清除的动作,导致标记和清除的俩个过程的执行效率都随着对象数量的增长而降低
- 内存空间碎片化问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致当以后在程序运行的过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发一次垃圾收集动作
3.标记-复制算法
半区复制,将可用内存按容量划分为大小相等的俩块,每次只使用其中的一块,当这一块内存用完了,就将还存活着的对象复制到另外一块上面去,然后再把已使用过的内存空间一次清理掉
缺点:
- 将可用内存缩小为了原来的一半,空间浪费有点大
- 如果内存中多数对象都是存活着的,那这种算法将会产生大量的内存间的复制的开销
Appel式回收,把新生代分为一块较大的Eden空间和俩块较小的Survivor空间,发生垃圾收集时,将eden和survivor中仍然存活的对象一次性复制到另外一块surivior空间上,然后直接清理掉eden和已使用过的那块survivor
4.标记-整理算法
步骤:不是直接对可回收对象进行清理,而是让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存
这个和标记-清除算法的本质差异是标记-清除是一种非移动式的回收算法,标记-整理式移动式的
对于标记-复制算法来说,在对象存活率较高时就要进行较多的复制操作,效率将会降低,对于老年代来说,每次回收都是会有大量对象存活的区域,移动存储对象并更新所有引用这些对象的地方将会式一种极为负重的操作,而且这种对象移动操作必须要全称暂停用户应用程序才能进行
最新的ZGC,Shenandoah收集器使用了读屏障技术实现了整理过程与用户线程的并发执行