垃圾回收器的两个指标

响应速度(Responsiveness)

系统对于输入数据的响应快慢,例如:

  • web服务器返回请求所消耗的时间
  • 一个数据库查询请求所消耗的时间

对于关注响应速度的系统而言,长时间的pause是不可接受的。

吞吐量(Throughput)

系统在指定的时间段内所能处理最大数量的任务。例如:

  • 在一个指定的时间段内系统所能完成的事务数量
  • 批处理系统中一个小时内完成的任务数量
  • 一个小时内能够完成的数据库查询总数

吞吐量指标通常关心的是一段较长时间范围内JVM的整体表现,因此单次Pause时间较长是可以被接受的。

G1 垃圾回收器

G1 的设计目标:运行于多处理器、大内存计算机上的垃圾回收器。兼顾了停顿时间与吞吐量。 自Jdk 7 update 4版本后提供完整支持,G1的设计要点:

  • 像CMS一样可以并发执行垃圾回收操作
  • 不会消耗冗长的时间用于压缩空闲空间
  • 可更精确地预测GC停顿耗时
  • 不会消耗太多的吞吐量表现(也就是说G1仍然是以响应速度为基准的,吞吐量被放在第二位)
  • 不会消耗过于夸张的JVM堆空间

相比于CMS,G1使用固定空间的region取代细粒度的链表来获取JVM堆中的剩余空间;而且G1提供了一种可预测GC停顿时间的算法,使得用户可根据自己的需要设置想要的停顿目标。

类似于CMS,G1垃圾收集器工作时通常也是从并发标记阶段开始,当这个阶段结束后,G1垃圾收集器就知道了每个region空间的使用情况。G1垃圾收集器通常从可产生最多空闲空间的region开始收集(即可回收空间最多),这也是G1名称的由来。G1将结合用户参数与其停顿预测模型来判断一次GC将作用于多少个region。

G1将采用evacuation的方式对成熟的region进行垃圾回收,即将多个region中仍然存活的对象copy至JVM堆中的另一个region中去,同时释放出自身region的空间。这一过程将采用并行的方式执行,尽量提高程序的吞吐量;G1将在用户预设的时间范围内,尽量减少碎片空间的产生(特别是相比于CMS),CMS在evacuation阶段将只会标记/清除掉不再存活的对象,同时产生大量的碎片化空间。而ParallelOld垃圾收集将对整个堆进行处理,导致超长的停顿时间。

请注意:G1垃圾回收器并不是一个实时垃圾回收器,它只会通过预测模型尽可能满足用户所设置的停顿时常,而不能100%满足。G1通过停顿模型预测每次垃圾收集的region数量,以达到尽可能满足用户停顿时长设置的目的。

  • RememberSets:RememberSets用于追踪一个region中所有对象的引用关系。RSet用于支持对region进行并发操作与收集,Rset对于整体标记阶段的影响小于5%
  • CollectionSets:CSets表示一个region的集合,集合中的region将在GC的过程中被收集,在一次GC中,CSets中所有的存活对象都将被evacuated(copied/moved)。这些Region可以属于Eden,Survivor,Old Generation中的任何一个区域,CSets只占用JVM整个空间中不足1%的大小。

官方建议遇到以下情况的CMS或者ParallelOldGC切换为G1:

  1. Full GC耗时非常长或者非常频繁
  2. 对象分配率或者提升量非常显著
  3. 垃圾收集或压缩的耗时特别长

回顾CMS

CMS垃圾收集器工作于老年代,通常搭配新生代的parallel收集器使用。它通过尽可能利用多线程进行并行操作来降低垃圾收集所带来的停顿时间。通常情况下CMS并不移动/复制存活的对象,自然也就不会压缩剩余的空闲空间,因此可能带来空间碎片增多的隐患,当碎片空间过多导致无法分配对象时,CMS将退化为效率非常低下的Serial Old垃圾收集算法对整个堆进行一次彻底清理。为避免极端情况发生,通常采用的方式是尽可能增加堆的大小。

CMS收集的各个阶段

  1. Initial Mark(Stop The World)初始化标记阶段将只会标记那些GC Roots(包括标记后的新生代对象)能够直接到达的老年代对象,停顿时间远远小于新生代停顿时间。
  2. Concurrent Marking 在不暂停工作线程的情况下,并行遍历并标记老年代所有对象。在2,3,5阶段中刚被分配或提拔至老年代的对象都将被直接标记为存活。
  3. Remark (Stop The World)找到并行标记阶段被漏掉的那些对象,把这些对象标记为存活。
  4. Concurrent Sweep 并发地清理掉所有被标记为”不可达”的对象,并将得到的空闲空间使用链表方式保存起来供下次分配使用。
  5. Restting 清理掉所有数据结构,供下次GC使用。