JVM垃圾收集器
本文讲述的是HotSpot虚拟机中的垃圾收集器。下图展示了7种不同分代的收集器,如果两个收集器之间存在连线,就说明它们可以搭配使用。
Serial收集器
- 单线程,只会使用一个CPU或者一条收集线程去完成垃圾收集工作。
- 进行垃圾收集时,必须暂停其他的所有线程,直到它收集结束。
- Client模式下默认的新生代收集器。
- 与其他收集器的单线程相比:简单而高效。
ParNew收集器
- Serial收集器的多线程版本。
- 运行在Server模式下虚拟机中首选的新生代收集器。
- 目前除了Serial收集器外,只有它能与CMS收集器配合工作。
- 在CPU环境中不会有比Serial收集器更好的效果。
Parallel Scavenge收集器
- 目的标则是达到一个可控制的吞吐量。(吞吐量=运行用户代码的时间 / (运行用户代码的世界 + 垃圾收集时间))。
- -XX:MaxGCPauseMillis,控制最大垃圾收集停顿时间。参数允许值为一个大于0毫秒数,GC停顿时间短是以牺牲吞吐量和新生代空间换取的。
- -XX:GCTimeRatio,设置吞吐量大小。参数为一个大于0且小于100的整数。
- 自适应调节策略:-XX:+UseAdaptiveSizePolicy。开启后就不需要手动指定新生代大小(-Xmn)、Eden与Survivor区的比例(-XX:SurvivorRatio)等细节参数了。这也是与ParNew收集器的一个重要区别。
并行:指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。
Serial Old收集器
- Serial收集器的老年代版本。
- 主要也是给Client模式下虚拟机使用。
- 在Server模式下:1. JDK1.5之前与Parallel Scavenge收集器搭配使用。2. 作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failue时使用。
Parallel Old收集器
- Parallel Scavenge收集器的老年代版本。使用多线程和"标记-整理"算法。
- 在注重吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge加Parallel Old收集器。
CMS收集器
- 目的:获取最短回收停顿时间。
- 基于"标记-清除"算法。
- 过程:
- 初始标记:标记一下GC Roots能直接关联到的对象,速度很快,需要"Stop The World"。
- 并发标记:进行GC Roots Tracing的过程。
- 重新标记:修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录。需要"Stop The World",停顿时间一般比初始标记长,但远比并发标记的时间短。
- 并发清除。
- 整个过程中耗时最长的并发标记和并发清除过程都可以与用户线程一起工作。总体上,CMS收集器的内存回收过程与用户线程一起并发执行的。
并发:指用户线程与垃圾收集线程同时执行(但是不一定是并行,有可能是交替执行),用户程序在继续运行,而垃圾收集程序运行于另一个CPU上。
- 缺点:
- 对CPU资源非常敏感。在CPU不足4个(比如2个)的时候,CMS对用户程序的影响就可能变得很大,如果CPU本来负载很大,还分出一半的运算能力去执行收集器线程,就可能导致用户程序的执行速度忽然降低50%。
- 无法处理浮动垃圾。并发清除阶段程序还在运行着,无法清除这是程序产生的垃圾,这些垃圾成为浮动垃圾。所以需要预留一部分空间提供并发收集时程序运作使用,要是预留内存无法满足程序需要,就会出现一次"Concurrent Mode Failure",这时虚拟机就会启动后备预案,临时启用Serial Old收集器来重新进行老年代的垃圾收集。
- CMS是基于"标记-清除"算法,可能会有大量空间碎片产生,这样会导致大对象可能无法分配,从而不得不提前触发一次FullGC。-XX:+UseCMSCompactAtFullCollection开关(默认是开启的),用于在CMS收集器顶不住要进行FullGC时开启内存碎片的合并整理过程。
G1收集器
- 面向服务端应用的垃圾收集器
- 特点:
- 并行与并发:充分利用多CPU,使用多个CPU来缩短Stop The World停顿的世界,在收集时,G1收集器可以通过并发的方式让Java程序继续执行。
- 分代收集:可以不需要其他收集器配合就能独立管理整个堆。
- 空间整合:G1收集器从整体上看是基于"标记-整理"算法,从局部(两个Region)上看是基于"复制"算法实现的。
- 可预测的停顿:可建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不超过N毫秒。G1跟踪各个Region里面的垃圾堆积的价值大小(回收所获得空间大小以及回收所需时间),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region。
- Region之间的对象引用以及其他收集器中的新生代与老年代之间的对象引用,虚拟机都是使用Remembered Set来避免全堆扫描的。G1中每个Region都有一个与之对应的Remembered Set。
- 不计算维护Remembered Set的操作,G1收集器运作步骤:
- 初始标记:标记一下GC Roots能直接关联到的对象。需要停顿线程,但耗时很短。
- 并发标记:从GC Roots开始对堆中对象进行可达性分析,找出存活的对象,耗时较长,但可以与用户程序并发执行。
- 最终标记:修正并发标记期间因用户程序继续运作而导致标记产生变化的那一部分标记记录,需要停顿线程,但可以并行执行。
- 筛选回收:首先对各个Region的回收价值和成本排序,根据用户期望的GC停顿时间来制定回收计划。