7.1 权衡与可插拔的收集器
在选择垃圾收集器时,通常需要考虑一下主要问题:
- 暂停时间(也叫暂停长度或持续时间)
- 吞吐量(垃圾收集时间占应用程序运行时间百分比)
- 暂停频率(收集器需要停止应用的频率)
- 回收效率(一个垃圾收集工作周期内可收集的垃圾量)
- 暂停的一致性(所有的暂停长度是否大致相同)
7.2 并发垃圾收集理论
7.2.1 JVM安全点
7.3 CMS
CMS收集器是专门为老年代空间设计的一个延迟极低的收集器,它通常会与一个稍微修改过的,用于Yong GC并行收集器(叫做ParNew ,而不是Parallel GC)配对使用。
CMS会在应用线程仍在运行的时候尽量多做一些工作,以便最大化地减少暂停时间,它使用的标记算法是三色标记。当然这就意味着在收集器正在扫描堆的同时,对象图可能会被修改。因此,CMS必须对戏进行修正,以避免破坏垃圾收集器的第二条规则,也就是把仍然活着的对象收集了。
这就导致了与并行收集器相比,CMS所需的阶段更为复杂。这些阶段如下。
- 初始标记(initial mark)(STW)
- 并发标记(concurrent mark)
- 并发预清理(concurrent preclean)
- 重新标记(remark)(STW)
- 并发清除(concurrent sweep)
- 并发重置(concurrent reset)
垃圾收集在大多数阶段是与应用线程同时运行的,但是在初始标记和重新标记这两个阶段中,所有应用程序线程都必须停止。总的效果应该是两个通长来说时间比较短的STW暂停来代替一次长时间的STW暂停。
7.3.2 用于CMS的基本JVM标志
CMS收集器可用以下标志开启
-XX:+UseConcMarkSweepGC
7.4 G1
G1是一款与并行收集器或CMS的风格都非常不同的收集器。它最初以高度实验性和不稳定的状态出现与Java6,但是Java7的整个开发过程中经过了大量重写,直到Java8u40的发布才真正称为稳定的、可供生成使用的版本。
无论考虑什么类型的工作负载,如果使用G1,不建议采用任何Java 8u40之前的版本
G1最初是打算成为一款替代用的低延迟收集器,具有如下特性:
- 调优比CMS更容易
- 不容易受到早期晋升的影响
- 行为在大堆上能更好地扩展(特别是暂停时间)
- 能够消除(或者极大减少回退到)完全STW的收集。
然而,随着时间的推移,G1逐渐被认为是一款通用的收集器,在更大的堆上有更少的暂停时间。
不管最终用户的影响如何,Oracle都坚持让G1取代并行收集器,称为Java9中的默认收集器。因此,性能分析人员需要充分理解G1,并且任何要从Java8迁移到Java9的应用程序都需要恰当的进行重新测试,这应该是迁移工作的一部分。
7.4.1 G1堆布局和区域
G1堆基于区域(region)的概念。这些区域的大小默认是1MB(在更大的堆上会更大)。区域的使用支持非连续的分代,从而使收集器可用不需要在每次运行时手机所有垃圾。
7.4.2 G1算法设计
从上得知
- G1使用了一个并发标记阶段
- G1是一款疏散收集器
- G1提供了“统计型压缩”
在预热的同时,收集器会跟踪并统计每个垃圾收集执行周期有多少“典型”的区域可被收集。如果能手机足够的内存以平衡自上次垃圾收集依赖分配的新对象,那G1就不会因为分配而失败。
7.4.3 G1的各阶段
G1可用划分为一系列阶段,和之前遇到的收集器有点类似。具体如下
- 初始标记(initial mark),STW
- 并发根扫描(concurrent root scan)
- 并发标记(concurrent mark)
- 重新标记(remark),STW
- 清理(cleanup),STW
并发根扫描是一个并发标记阶段,该阶段会扫描初始标记的Survivor区域以寻求指向老年代的引用。这个阶段必须在下一次Yong GC开始之前完成,在重新标记阶段,标记周期完成。这个阶段还执行引用处理(包括弱引用和软引用),并进行与实现SATB方法有关的清理工作。
清理工作大多是STW的,它包括处理记账信息和擦洗 RSet。记账处理任务会识别现在已经完全空闲并准备好复用的区域(比如用作Eden区域)。
7.4.4 用于G1的基本标志
在Java8和更早的版本中,需要使用如下开关来启用G1:
+XX:UseG1GC
G1是围绕暂停时间目标设计的。这使得开发人员可以指定应用程序在每个垃圾收集周期中应该暂停的最大时间。虽然是一个目标,但是JVM并不能保证应用程序能够达到这个目标,如果这个值设置得太低,那么垃圾收集子系统将无法达到目标。
控制G1收集器这一核心行为的开关是
XX:MaxGCPauseMillis=200
这意味着默认的暂停时间目标是200毫秒。另一个可能有用的选择是修改区域的大小,可以这样覆盖默认算法
-XX:G1HeapRegionSize=<n>
n必须是2的幂,范围在1到64之间,表示一个单位为MB的值。
