七种常见的垃圾收集器:Serial收集器、Serial Old收集器、ParNew收集器、Parallel Scavenge收集器、Parallel Old收集器、CMS收集器、G1收集器。
一、Serial收集器(新生代)
Serial(串行)收集器采用“标记-复制”算法负责新生代的垃圾收集。它是HotSpot虚拟机运行在客户端模式下的默认新生代收集器。
它是一个单线程收集器。在它进行垃圾收集工作的时候,必须暂停其他所有的工作线程,直到收集结束。
二、Serial Old收集器(老年代)
Serial Old是一个单线程收集器,它采用“标记-整理”算法负责老年代的垃圾收集,主要用于客户端模式下的HotSpot虚拟机使用。
如果在服务器端使用,它主要有两种用途:
- 在JDK5及以前版本,与Parallel Scavenge收集器搭配使用;
- 作为CMS收集器发生失败时的后备预案。
三、ParNew收集器(新生代)
ParNew收集器是一个多线程的垃圾收集器,它采用“标记-复制”算法,运行在Server模式下的虚拟机的首要选择,可以与Serial Old,CMS垃圾收集器一起搭配工作。
四、Parallel Scavenge收集器(新生代)
Parallel Scavenge收集器是一个多线程的垃圾收集器,它采用“标记-复制”算法。
目标:使垃圾收集的时间达到一个可控制的吞吐量。
吞吐量=运行用户代码时间/(用户代码时间+运行垃圾收集时间)
五、Parallel Old收集器(老年代)
Parallel Old收集器是一个多线程的垃圾收集器,它采用“标记-整理”算法,是Parallel Scavenge收集器的老年代版本;
在注重吞吐量或者处理器资源较为稀缺的应用场景,都可以优先考虑Parallel Scavenge收集器+Parallel Old收集器这个收集器组合。
六、CMS收集器(老年代)
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收时间为目标的收集器,基于“标记-清除”算法实现,是HotSpot虚拟机第一款真正意义上的并发收集器,它实现了让垃圾收集线程与用户线程基本上同时工作。
工作流程:
- 初始标记(CMS initial mark):标记一下GC Roots能直接关联到的对象,速度很快;
- 并发标记(CMS consurrent mark):从GC Roots的直接关联对象开始遍历整个对象图的过程,这个过程耗时较长,但是不需要停顿用户线程,可以与垃圾收集线程一起并发运行;
- 重新标记(CMS remark):重新标记阶段,是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段的时间长,远远比并发标记阶段时间短;
- 并发清除(CMS concurrent sweep):清理删除掉标记阶段判断的已经死亡的对象,由于不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的。
主要优点:并发收集、低停顿。
主要缺点:
- 影响用户线程的执行效率:并发标记和并发清除时,是和用户线程一起运行的,收集过程中会占用用户程序的CPU资源;
- 无法处理浮动垃圾:在并发清除阶段,用户线程并没有停止,还会继续产生新的垃圾,只能等待下一次收集时才能进行回收,这部分垃圾被称为“浮动垃圾”;
- 产生大量空间碎片:因为CMS收集器是基于“标记-清除”算法实现的,所以在进行大量的垃圾回收时,会产生很多不连续的内存空间。这是使用“标记-清除”算法都会有的缺点。
七、G1收集器(老年代)
G1(Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器、大容量内存的机器。它不再严格按照分代思想进行垃圾回收。G1采用局部性收集的设计思路和基于Region的内存布局形式。
工作流程:
- 初始标记(Initial Marking):这个阶段仅仅只是标记GC Roots能直接关联到的对象,这阶段需要停顿线程,但是耗时很短。
- 并发标记(Concurrent Marking):从GC Roots开始对堆的对象进行可达性分析,递归扫描整个堆里的对象图,找出存活对象,这阶段耗时较长,但是可以与用户程序并发执行。
- 最终标记(Final Marking):堆用户线程做另一个短暂的暂停,用于处理并发阶段结束后遗留记录。
- 筛选回收(Live Data Counting and Evacuation):负责更新Region的统计数据,对各个Region的回收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划。可以自由选择多个Region来构成回收集,然后把回收的那一部分Region中的存活对象复制到空的Region中,最后对那些Region进行清空。