垃圾收集器概述
大部分的垃圾收集器一般都只是针对新生代或者老年代其中一个区域的,因此需要搭配其它的垃圾收集器来收集另外一块区域,只有极少数的垃圾收集器可以既回收新生代又回收老年代。虚拟机包含的所有垃圾收集器如下:
注意: 如果两个垃圾收集器之间有连线,表示它们可以搭配使用
解释: 并行(Parallel):多条垃圾收集线程并行工作,而用户线程仍处于等待状态
并发(Concurrent):垃圾收集线程与用户线程一段时间内同时工作(交替执行)
Serial收集器
这个收集器是一个单线程的收集器,它的单线程意义并不说明它只会使用一个CPU或一条收集线程去完成垃圾收集工作,更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。Serial收集器简单而高效,在单个CPU的环境下,Serial收集器由于没有线程交互的开销,单线程收集更高效。对于运行在Client模式下的虚拟机来说是一个很好的选择。一般会搭配Serial Old垃圾收集器来使用:
ParNew收集器
ParNew是Serial的多线程版本,用的控制参数、收集算法、Stop The World、对象分配规则、回收策略等都与Serial收集器完全一样,他们共用了很多代码。ParNew收集器是Server模式下的虚拟机首选的新生代收集器,除了Serial外,只有它能与CMS收集器配合工作。
单CPU环境下,可能存在线程交互的开销,比不上Serial收集器。随着CPU数量增多,它默认开启收集线程数与CPU的数量相同,在CPU非常多的情况下,可以使用-XX:ParallelGCThreads参数来限制垃圾收集的线程数。
注意:
- 并行收集器:指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。
- 并发收集器:指用户线程与垃圾收集线程同时执行(不一定并行,可能交替执行),用户程序继续运行,而垃圾收集程序运行在另一个CPU上。
Parallel Scavenge收集器
Parallel Scavenge是新生代、使用复制算法、并行的多线程收集器。它的目标是达到一个可控制的吞吐量。
注意: 吞吐量 = 运行用户代码时间/(运行用户代码时间+垃圾收集时间)
Parallel Scavenge提供两个参数用于精确控制吞吐量,分别是控制最大垃圾收集停顿时间的-XX:MaxGCPauseMillis参数以及直接设置吞吐量大小的-XX:GCTimeRatio参数。
Parallel Scavenge被称为“吞吐量优先”的收集器,它的-XX:+UseAdaptiveSizePolicy参数动态调整新生代、老年代等的参数来提供最合适的停顿时间或者最大吞吐量,这种调节方式称为“GC自适应的调节策略”。
Serial Old收集器
Serial Old是Serial的老年代垃圾收集器,单线程,使用“标记-整理”算法。可以作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure时使用。
Parallel Old收集器
Parallel Old是老年代的Parallel Scavenge收集器的老年代版本,多线程,“标记-整理”算法。在注重吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge加Parallel Old收集器。
CMS收集器
CMS(Concurrent Mark Sweep)收集器是一种获取最短回收停顿时间为目标的收集器。CMS基于“标记-清除”算法,它的运作过程分为4个步骤:
- 初始标记(CMS initial mark):需要STW,仅仅标记GC Roots能直接关联到的对象,速度很快
- 并发标记(CMS concurrent mark):进行GC Roots Tracing的过程,耗时长,可以与用户线程一起工作
- 重新标记(CMS remark):需要STW,为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般比初始标记阶段稍长一些,但远比并发标记的时间短。
- 并发清除(CMS concurrent sweep):耗时长,可以与用户线程一起工作
G1收集器
G1是一款面向服务端应用的垃圾收集器。与其他收集器相比,G1具备一下特点:
- 并行与并发:充分利用多核CPU优势,缩短STW的停顿时间,部分其他收集器需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让Java程序继续执行
- 分代收集:能够采用不同的方式去处理新创建的对象和已经存活了一段时间、熬过多次GC的旧对象以获取更好的收集效果
- 空间整合:G1整体来看是基于“标记-整理”算法实现的收集器,局部来看是基于“复制”算法,这两种算法都意味着G1运行期间不会产生内存空间碎片
- 可预测的停顿:G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定一个长度M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒
G1收集器的运作大致划分为一下几个步骤:
- 初始标记:标记一下GC Roots能直接关联到的对象,并且修改TAMS(Next Top at Mark Start)的值,让下一阶段的用户进程并发运行时,能在正确可用的Region中创建新对象,这阶段需要停顿线程,但耗时很短。
- 并发标记:从GC Roots开始对堆中对象进行可达性分析,找出存活的对象,这个阶段耗时较长,但可与用户程序并发执行。
- 最终标记:为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程Remembered Set Logs里面,最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set,这阶段需要停顿线程,但是可以并行执行。
- 筛选回收:首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划。可以做到与用户程序一起并发执行,但是因为只回收一部分Region,时间是户可控制的,但是停顿用户线程将大幅提高收集效率。