G1垃圾收集器要点总结

HotSpot提供了一种垃圾回收策略,G1(Garbage First)算法,通过参数-XX:+UseG1GC来启用,该算法在JDK 7u4版本被正式推出。

G1收集器特点

  • 并行和并发: 具有CMS一样的多线程操作能力

  • 压缩:在保持短的停顿时间的基础上尽可能消除碎片

  • 可预测性:GC停顿时间更加可预测

  • 高效:不会对系统吞吐量产生较大影响

  • 节约:GC操作不会浪费太多的heap空间

一、Remembered Set

在G1收集器中,Region之间的对象引用以及其他收集器中的新生代与老年代之间的对象引用,虚拟机都是使用Remembered Set来避免全堆扫描的。
G1中每个Region都有一个与之对应的Remembered Set,虚拟机发现程序在对Reference类型的数据进行写操作时,会产生一个Write Barrier暂时中断写操作,检查Reference引用的对象是否处于不同的Region之中(在分代的例子中就是检查是否老年代的对象引用了新生代中的对象),如果是,便通过CardTable把相关引用信息记录到被引用对象所属的Region的Remembered Set之中。
当进行内存回收时,在GC根节点的枚举范围中加入Remembered Set即可保证不对全堆扫描也不会遗漏。
如果不计算维护Remembered Set的操作,G1收集器的运作大致可划分为以下几个步骤:

  • 初始标记(Initail Marking)
  • 并发标记(Concurrent Marking)
  • 最终标记(Final Marking)
  • 筛选回收(Live Data Counting and Evacuation)

对CMS收集器运作过程熟悉的读者,一定已经发现G1的前几个步骤的运作过程和CMS有很多相似之处。
初始标记阶段仅仅只是标记一下GC Roots能直接关联到的对象,并且修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的Region中创建新对象,这阶段需要停顿线程,但耗时很短。
并发标记阶段是从GC Root开始对堆中对象进行可达性分析,找出存活的对象,这阶段耗时较长,但可与用户程序并发执行。
而最终标记阶段是为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程Remembered Set Logs里面,最终标记阶段需要把Remenbered Set Logs的数据合并到Remenbered Set中,这阶段需要停顿线程,但是可并行执行。
最后在筛选回收阶段首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划,从Sun公司透露出来的信息来看,这个阶段其实也可以做到与用户程序一起并发执行,但是因为只回收一部分Region,时间是用户可控制的,而且停顿用户线程将大幅度提高收集效率。

注意:G1同时有并发(与应用程序线程一起运行,例如细化,标记,清理)和并行(多线程,例如STW)的阶段。FullGC仍然是单线程的,但是如果您的应用程序正确调优,应避免使用Full GC。

二、G1 踪迹

如果从Parallel Old收集器或CMS收集器迁移到G1,则可能会看到更大的JVM进程大小。这主要与"accounting"数据结构相关,如Remembered Sets(RSets)和Collection Sets(CSets)。

Remembered Sets (RSets)跟踪对象引用到给定的区域。堆中每个区域有一个RSet。 RSet使GC能并行和独立地收集一个区域。 RSets的整体性能影响小于5%
Collection Sets (CSets)是GC中将要被收集的一组区域。GC中的所有存活数据在GC期间转移(复制/移动)。这些集合可能是eden区,survivor区或者老年代,CSets对JVM的大小影响不到1%。

三、G1区域划分图解

G1垃圾收集器要点总结_第1张图片
堆 空 间 被 分 割 成 一 些 相 同 大 小 的 堆 区 域 , 每 一 个 都 是 连 续 范 围 的 虚 拟 内 存 。 特 定 的 区 域 集 合 像 旧 的 收 集 器 一 样 被 指 派 为 相 同 的 角 色 \color{red}{堆空间被分割成一些相同大小的堆区域,每一个都是连续范围的虚拟内存。特定的区域集合像旧的收集器一样被指派为相同的角色} (伊甸:eden、幸存:survivor、年老:old),但是它们没有一个固定大小。这在内存使用上提供了更强大的灵活性。

四、使用G1注意点

  • 不用指定年轻代大小:在G1中年轻代是在5%-60%的区间中可伸缩的,G1自己会调控到合适的大小所以不要指定。可以指定堆内存大小
  • -XX:InitiatingHeapOccupancyPercent=45:设置触发标记周期的 Java 堆占用率阈值。默认占用率是整个 Java 堆的 45%,应该是老年代占用达到45%时进行垃圾混合收集,在此之前都是对enden区进行收集。

推荐阅读

G1垃圾回收器详解
关于G1 GC中Mixed GC的分析

参考文献

G1收集器
G1 垃圾收集器入门
Oracle技术网

你可能感兴趣的:(jvm)