图文超详解 G1 垃圾收集器深入剖析( 二 )


堆内存中一个区域 (Region) 的大小,可以通过 -XX:G1HeapRegionSize 参数指定,大小区间最小 1M 、最大 32M,总之是 2 的幂次方 。
默认是将堆内存按照 2048 份均分 。
2.2  G1 堆内存分配每个 Region 被标记了 E、S、O 和 H,这些区域在逻辑上被映射为 Eden,Survivor 和老年代 。
存活的对象从一个区域转移(即复制或移动)到另一个区域 。区域被设计为并行收集垃圾,可能会暂停所有应用线程 。如上图所示,区域可以分配到 Eden,survivor 和老年代 。
此外,还有第四种类型,被称为巨型区域(Humongous Region) 。
Humongous 区域主要是为存储超过 50% 标准 region 大小的对象设计,它用来专门存放巨型对象 。如果一个 H 区装不下一个巨型对象,那么 G1 会寻找连续的 H 分区来存储 。为了能找到连续的 H 区,有时候不得不启动 Full GC。
G1 回收流程在执行垃圾收集时,G1 以类似于 CMS 收集器的方式运行 。
1. G1 收集器的阶段,大致分为以下步骤:

图文超详解 G1 垃圾收集器深入剖析

文章插图
1.1  G1 执行的第一阶段:初始标记 ( Initial Marking )这个阶段是 STW(Stop the World ) 的,所有应用线程会被暂停,标记出从 GC Root 开始直接可达的对象 。
1.2  G1 执行的第二阶段:并发标记从 GC Roots 开始,对堆中对象进行可达性分析,找出存活对象,耗时较长 。
当并发标记完成后,开始最终标记 ( Final Marking ) 阶段 。
1.3  最终标记标记那些在并发标记阶段发生变化的对象,将被回收 。
1.4  筛选回收首先,对各个 Regin 的回收价值和成本进行排序,根据用户所期待的 GC 停顿时间,来指定回收计划,回收一部分 Region。
G1 中提供了 Young GC、Mixed GC 两种垃圾回收模式,这两种垃圾回收模式,都是 Stop The World(STW) 的 。
G1 的 GC 模式1. YoungGC 年轻代收集在分配一般对象(非巨型对象)时,当所有 eden region 使用达到最大阀值、并且无法申请足够内存时,会触发一次 YoungGC。
每次 younggc 会回收所有Eden 、以及 Survivor 区,并且将存活对象复制到 Old 区以及另一部分的 Survivor 区 。
YoungGC 的回收过程:
  • 根扫描,跟 CMS 类似,Stop the world,扫描 GC Roots 对象;
  • 处理 Dirty card,更新 RSet;
  • 扫描 RSet,扫描 RSet 中所有 old 区,对扫描到的 young 区或者 survivor 区的引用;
  • 拷贝扫描出的存活的对象到 survivor2/old 区;
  • 处理引用队列、软引用、弱引用、虚引用 。
2. mixed gc当越来越多的对象晋升到老年代 old region 时,为了避免堆内存被耗尽,虚拟机会触发一个混合的垃圾收集器,即 mixed gc,该算法并不是一个 old gc,除了回收整个 young region,还会回收一部分的 old region。
这里需要注意:是一部分老年代,而不是全部老年代,可以选择哪些 old region 进行收集,从而可以对垃圾回收的耗时时间进行控制 。
G1 没有 fullGC 概念,需要 fullGC 时,调用 serialOldGC 进行全堆扫描(包括 eden、survivor、o、perm) 。
G1 的推荐用例G1 的第一个重要特点:是为用户的应用程序的提供一个低GC延时和大内存GC的解决方案 。
这意味着堆大小 6GB 或更大,稳定和可预测的暂停时间将低于 0.5 秒 。
如果应用程序使用 CMS 或 ParallelOld 垃圾回收器,具有一个或多个以下特征,将有利于切换到 G1:
  • Full GC 持续时间太长或太频繁;
  • 对象分配率或年轻代升级老年代很频繁;
  • 不期望的很长的垃圾收集时间或压缩暂停(超过 0.5 至 1 秒) 。
注意:
如果你正在使用 CMS 或 ParallelOld 收集器,且应用程序没有遇到长时间的垃圾收集暂停,则保持当前收集器就可以了 。升级 JDK,并不需要更新收集器为 G1。

经验总结扩展阅读