Serial垃圾回收器是最基本的、历史最悠久的垃圾收集器。JDK1.3之前回收新生代唯一的选择。Serial垃圾回收器是一个单线程的收集器,它进行垃圾收集时必须暂停其他所有的工作线程,直到它收集结束。Serial 用于新生代回收,采用复制算法;Serial Old 用于老年代回收,采用标记-整理算法。
Serial 一般用在客户端程序或占用内存较小的微服务,因为客户端程序一般分配的内存都比较小,可能几十兆或一两百兆,回收时的停顿时间是完全可以接受的。而且 Serial 是所有回收器里额外消耗内存最小的,也没有线程切换的开销,非常简单高效。
Parallel垃圾回收器也被称为吞吐量优先的垃圾回收器(吞吐量是指CPU用于执行用户代码的时间和CPU总消耗时间的比值),其目标是达到一个可控制的吞吐量。Parallel Scavenge 用于新生代回收,采用复制算法;Parallel Old 用于老年代回收,采用标记-整理算法。
Parallel垃圾回收器采用自适应调节策略,高吞吐量可以高效率地利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。因此,Parallel垃圾回收器常见在服务器环境中使用。
JDK 8的默认垃圾回收器是Parallel Scavenge + Parallel Old,即使用Parallel Scavenge(新生代)+ Parallel Old(老年代)
CMS(Concurrent Mark Sweep)垃圾回收器是一种老年代垃圾回收器,它可以在垃圾回收过程中与用户线程并发执行,主要牺牲了系统的吞吐量来追求收集速度,适合追求垃圾收集速度的服务器。
由于CMS使用标记-清除算法,会产生内存碎片,分配对象时内存不足,造成并发失败触发Full GC,这时老年代并发垃圾回收器会退化到Serial Old串行垃圾回收器,使用标记-整理算法并进行整理,整理至碎片减少,才能继续工作,但这会导致垃圾回收的整体时间变长。CMS已经在JDK9中被标记为废弃。
G1是一个并行与并发的标记-复制垃圾回收器,它的设计目标是为了适应不断扩大的内存和不断增加的处理器数量,进一步降低暂停时间(pause time),同时兼顾良好的吞吐量。在JDK 9及以后的版本中,G1垃圾回收器成为了默认的垃圾回收器。
G1回收器将堆内存划分为多个固定大小的Region,每个Region可以是年轻代或老年代的一部分。在进行垃圾回收时,G1可以同时使用多个GC线程,有效利用多核计算能力。
ZGC(Z Garbage Collector)是一款在JDK 11中加入的低延迟的垃圾收集器,在JDK 15中成为具有商用的垃圾收集器。ZGC是一款并发的垃圾收集器,主要为了满足如下目标进行设计:
ZGC使用颜色指针进行标记对象的垃圾状态,当这个被指向的内存发生变化的时候,颜色也就会发生变化。
Epsilon垃圾回收器控制内存分配,但是不执行任何垃圾回收工作。设计的目的是提供一个完全消极的GC实现,分配有限的内存分配,最大限度降低消费内存占用量和内存吞吐时的延迟时间
标记–清除算法分为标记和清除两个阶段,标记阶段遍历内存区域,对需要回收的对象打上标记。清除阶段再次遍历内存,对已经标记过的内存进行回收。 缺点是容易产生大量内存碎片
复制算法将内存划分为等大的两块,每次只使用其中的一块。当一块用完了,触发GC时,将该块中存活的对象复制到另一块区域,然后一次性清理掉这块没有用的内存。缺点是内存利用率不高,每次只能使用一半内存。
标记–整理算法分为标记阶段和整理阶段两个阶段:标记阶段与标记-清除算法一样,从根对象开始,遍历所有直接或间接引用的对象,将它们进行标记。整理阶段在回收不存活的对象占用的空间后,将所有的存活对象往一端空闲空间移动,并更新对应的指针。
标记-整理算法是在标记-清除算法的基础上,又进行了对象的移动,因此成本更高,但是却解决了内存碎片的问题。
分代收集算法算法并没有新的内容,只是根据对象的存活周期的不同,将内存分为新生代和老年代。新生代中的对象存活时间较短,老年代中的对象存活时间较长。针对不同代采取不同的收集算法。
-XX:MaxGCPauseMillis:用于设置最大GC暂停时间的目标。默认值是200ms.
-XX:G1SurvivorRatio:用于设置Eden区与Survivor区的比例。默认值是8,survivor TO区:survivor FROM区:老年代 = 1:1:8
-XX:InitiatingHeapOccupancyPercent:启动并发GC周期时的堆内存占用百分比,默认值是45%。