0%

jvm03_CMS&G1回收流程

CMS

CMS(Concurrent Mark Sweep)收集器是以获取最短回收停顿时间为目标的收集器。(希望系统停顿时间尽可能短,以给用户带来良好的体验)

特点

  1. 以低停顿为目标

  2. 使用标记清除算法标记整理算法

    一般使用标记清除算法,由于不需要移动对象。可以达到和用户线程并发的效果。但是随着内存碎片的增加,Full GC一定次数以后,会只用标记整理算法。

回收流程

  • 初始标记(需要STW)

    标记一下GC Roots能直接关联到的对象,速度很快。

  • 并发标记

    并发标记是从GC Roots的直接关联对象开始遍历整个对象图的过程,耗时较长但是不需要停顿用户线程

  • 重新标记(需要STW)

    修正并发标记期间,因用户线程继续运作而导致标记产生变动的那一部分对象的标记记录。

  • 并发清除

    清理删除标记阶段半段的已经死亡的对象,由于不需要移动存活对象,这个阶段也是可以和用户线程并发的

缺点

对处理器资源敏感

CMS默认启动的回收线程数是(CPU数量+3)/4,当CPU在4个以上时,并发回收时垃圾收集线程不少于25%的CPU资源。当CPU不足4个时(比如两个),CMS对用户程序的影响会变的很大。

无法处理浮动垃圾

CMS收集器无法处理浮动垃圾,可能出现“Concurrent Mode Failure”失败而导致另一次Full GC的产生。

什么是浮动垃圾?
伴随着程序运行,会产生一些新的垃圾,这些垃圾出现标记过程之后,CMS无法在当次清除他们,只能留到下一次GC再清理,这部分垃圾称为 浮动垃圾

CMS不会等老年代几乎满了才开始收集,需要预留一部分空间提供并发收集时程序运行使用。

在JDK1.5的默认设置下,CMS收集器当老年代使用了68%的空间后会被激活。JDK1.6中,阈值为92%。(可以通过-XXCMSInitiatingOccupancyFraction参数进行调整,阈值太高容易出现Concurrent Mode Failure失败,导致性能降低)

当预留的内存无法满足程序运行需要,就会出现一次“Concurrent Mode Failure”失败。这时虚拟机会启用后备预案:临时启用Serial Old收集器进行老年代垃圾收集

使用标记整理算法产生大量内存碎片

当虚拟机内存碎片很严重的时候,创建大对象时,虚拟机找不到足够大的内存空间而不得不提前触发一次Full GC。

为解决这个问题,CMS提供了两个参数。

  • -XX:+UseCMSCompactAtFullCollection(开关参数 默认开启),CMS进行FULL GC时开启内存碎片的合并整理过程。
  • -XX:CMSFullGCsBeforeCompaction,这个参数用于设置执行多少次不压缩的Full GC后,跟着来一次带压缩的(默认值为0,每次Full GC都进行整理)

Garbage First收集器(G1)

G1特点

  1. 基于“停顿时间模型”的收集器(停顿时间可控)

    停顿时间模型指的是能够支持在指定一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间大概率不超过N毫秒

  2. 分区分代

    G1把连续的java堆划分为多个大小相等的独立区域(Region),每一个区域都可以根据需要扮演新生代的Eden空间、Survivor空间或者老年代空间。

    Region中有一类特殊的Humongous区域,专门用来存储大对象。只要大小超过了一个Region容量的一半就会被判断为大对象。对于超过了整个Region的超级大对象,会用连续N个Humongous来存放。

  3. 面向整个堆内存任何部分组成回收集(Collection Set),进行回收,衡量标准不再是属于哪个分代,而是哪块内存中存放的垃圾数量最多,回收收益最大

  4. 从整体看是基于“标记-整理”算法,从局部看是“标记-复制”算法

  5. G1类似小步快跑的模式,Gc更加频繁,但是停顿可控,对于大内存JAVA堆更加友好(6G以上,如果内存过大CMS回收起来比较慢)

G1为什么能建立可预测的停顿模型?

G1之所以能建立可预测的停顿模型,是因为它将Region作为单次回收的最小单元,每次收集到的内存空间都是Region的整数倍,避免在整个JAVA堆中进行垃圾收集。每个Region都被G1标记相应的回收“价值”大小,并在后台维护一个优先级列表,每次根据用户设定的收集停顿时间,优先处理回收价值收最大的Region。

回收流程

  • 初始标记(需要STW)

    标记一下GC Roots能直接关联到的对象,并修改TAMS指针的值,速度很快。

  • 并发标记

    并发标记是从GC Roots的直接关联对象开始遍历整个对象图的过程,耗时较长,可以和用户线程并发执行。扫描完后,需要重新处理SATB下的在并发时有引用变动的对象。

  • 最终标记(需要STW)

    对用户线程做一个短暂的暂停,用于处理并发阶段结束后仍遗留下来的最后那少量的SATB记录。

  • 筛选回收(需要STW)

    更新Region的统计数据,对各个Regin的回收价值和成本进行排序,根据用户所期待的GC停顿时间指定回收计划,回收一部分Region。这个过程需要把原来Region中的对象复制到新的Region中,并清空旧的Region,涉及到对象移动,必须要暂停用户线程。

TAMS

此外,由于并发标记时用户线程仍在继续执行,肯定会持续创建新对象。

G1 为每个 Region 设计了两个名为 TAMS(Top at Mark Start)的指针,把 Region 中的一部分空间划分出来用于并发回收过程中的新对象分配(默认都是存活的,不纳入回收范围)。

与CMS的 Concurrent Mode Failure类似,如果内存回收速度赶不上内存分配的速度,G1 收集器也要被迫冻结用户线程执行,导致 Full GC 而产生长时间“Stop The World”。

SATB

并发标记时用户线程仍在继续执行,需要解决用户线程改变对象应用关系时,不能打破原本对象的图结构导致标记出错。

CMS采用增量更新算法实现,G1采用原始快照算(SATB)法实现。

G1缺点

  1. 内存占用高

    堆中每个Region,无论扮演新生代还是老年代,都必须有一份卡表,导致G1的记忆集可能会占整个堆容量的20%乃至更多内存空间。

  2. 执行额外负载更高

    G1对写屏障的操作复杂度比CMS消耗更多运算资源

Hotspot算法细节实现

根节点枚举

Safepoint原理

并发可达性分析