算法
标记和清除
GC分为两个阶段,标记和清除。首先标记所有可回收的对象,在标记完成后统一回收所有被标记的对象。同时会产生不连续的内存碎片。碎片过多会导致以后程序运行时需要分配较大对象时,无法找到足够的连续内存,而不得不再次处罚GC.
复制
将内存按容量划分为两块,每次只是用其中的一块。当这一块内存用完了,就将存活的对象复制到另一块上,然后再把已使用的内存空间一次清理掉。这样使得每次都是对半内存区回收。也不用考虑内存碎片的问题,简单高效。缺点是需要两倍的内存空间。
标记-整理
也分为两个阶段,首先标记可回收的对象,再将存活的对象都向一端移动,然后清理掉边界以外的内存。此方法避免标记-清楚算法的碎片问题,同时也避免了复制算法的空间问题
一般年轻代中执行GC后,会有少量的对象存活,就会选用复制算法,只要付出少量的存活对象复制成本就可以完成收集。而老年代中因为对象存活率高,没有额外的过多内存空间分配,就需要使用标记-清理或者标记-整理算法来进行回收
垃圾回收器
串行收集器
比较老的收集器,单线程。收集时必须暂停应用的工作线程,直到收集结束
并行收集器
多条垃圾收集线程并行工作,在多核CPU下效率更高,应用线程仍然处于等待状态。
CMS收集器
CMS收集器是缩短暂停应用时间为目标而设计的,是基于标记-清除算法实现的,整个过程分为4个步骤,
- 初始标记
- 并发标记
- 重新标记
- 并发清除
其中 初始标记、重新标记这两个步骤仍然需要暂停应用线程。初始标记只是标记一下 GC Roots 能直接关联到的对象,速度很快。并发标记阶段是标记可回收对象,而重新标记阶段则是为了修正并发标记期间因用户程序继续运行导致的标记产生变动的那一部分对象的标记记录,这个阶段暂停时间比初始标记阶段稍长一点,但远比并发标记时间短
由于整个过程中消耗最长的并发标记和并发清除过程收集线程都可以与用户线程一起工作,所以CMS收集器内存回收与用户一起并发执行的,大大减少了暂停时间
G1 收集器
G1收集器将堆内存划分多个大小相等的独立区域,并且能预测暂停时间,能避免对整个堆进行全区收集。G1跟踪各个Region里的垃圾堆积价值大小(所获得空间大小以及回收所需时间),在后台维护一个优先列表,每次根据允许的收集优先回收价值最大的Region,从而保证了再有限时间内获得更高的收集效率
G1回收器的4个工作步骤
- 初始标记
- 并发标记
- 最终标记
- 筛选回收
初始标记与CMS 一样,标记一下GC Roots 能直接关联到的对象。并发标记冲GC Roots开始标记存活对象,这个阶段耗时比较长,但是也可以与应用线程并发执行。而最终标记也是为了修正在并发标记期间,因用户程序继续运行而导致标记产生变化的那一部分标记记录。最后在筛选回收阶段对各个Region回收价值和成本进行排序,根据用户所期望的GC暂停时间来执行回收