G1垃圾回收器

61 阅读4分钟

Oracle垃圾回收文档

阅读文档,记录一些重要的点。

G1的使用场景,在多核处理器的情况下

  1. 几十G或者更大的内存,堆超过50%被活动数据占据。
  2. 对象分配和晋升的速率可能会随时间发生显著变化。 应该就是指对象被长期使用,不是朝生夕死的那种。
  3. 堆中存在大量碎片。
  4. 可预测的暂停目标,不需要几百毫秒。

JDK9以上是默认的,可以用-XX:+UseG1GC手动指定使用

特点

  1. 分代
  2. 并行
  3. 大多数并发
  4. 会stop-the-world

根据应用历史行为,垃圾回收信息,优先回收性价比最高的区域,就是垃圾最多的。

G1主要通过回收机制来释放空间:将选定内存区域中发现的可收集活对象复制到新内存区域,并在过程中进行压缩。完成回收后,应用程序可重新利用原先被活对象占用的空间进行分配。

G1不是实时的垃圾回收期,会尝试实现暂停的目标,但是不保证一定完成。

image.png

灰色的是没有使用的,请求来的时候,管理器会把小region标记为yong代或者old代,然后返回给应用程序使用。 红色的就是yong代,红色带s的是yong代中的servivor区域. 蓝色的old代,蓝色带h的是放大对象的humongous区域。

除了巨大对象,都是分配到年轻代的eden区

G1回收的两个阶段

  1. young-only
    a. Concurrent Start 启动年轻代的收集,同时标记老年代还活着的对象
    b. Remark stop-the-world 说明标记结束了,这个时候会释放引用,卸载类,
    c. Cleanup stop-the-world 决定是否进入空间回收阶段,如果进入空间回收阶段,如果回收的话,就会变成single Prepare Mixed young collection操作
  2. Space-reclamation phase
    除了清理yong region以外,还会复制转移old region中存活的对象,也叫Mixed collections,直到G1认为回收性价比不高的时候停止 如果统计信息的时候,发生了out of memeroy 则执行一次full gc

image.png

垃圾收集和空间释放,都是在stop-the-world的时候执行的。此外

  1. 年轻代的对象,根据代数决定移动到servivor或者old
  2. old只能移动到old
  3. 超大对象humogous region如果对象不用了,可以回收,否则除非万不得已,是不移动的。

每一个region都被划分成512byte的card,这些card是标记的最小单位

Remenber Set

  1. 记录哪些region的card引用了本region中的对象,并不会存储引用所在的位置,而只是记录大概的位置,在哪些card里。
  2. 懒创建的,在Remark和Clean Up暂停的中间,G1重建所有被选中的Region中的Collect Set对应的Remenber Set 3.每个region都有一个RemenberSet存储了所有引用这个region的位置,CollectSet就是根据这个生成的。

Collect Set

  1. Collect Set 是一个要回收的region集合。依赖垃圾回收阶段的类型 在yong only阶段,collect set 仅由 年轻代的region,可能回收的的大对象的humongous region 组成 在Space-Reclamation阶段,collect set 由 年轻代的region,可能回收的的大对象的humongous region,和一些候选的老年代region组成。

  2. 在 G1 的空间回收阶段,系统会挑选一批“候选区域”作为潜在的回收目标。
    选择时考虑:

  • 区域内活对象少(可回收多);
  • 区域之间引用关系少(调整代价低)。

对那些能回收空间太少(低于 G1HeapWastePercent 阈值)的区域,G1 会直接放弃,不在本次回收中处理。

在Remark和CleanUp两次暂停中间,G1开始为接下来的收集准备。 随着Clean UP的暂停结束这个工作,并且结束根据region的回收价值排序,在随后的Mix collections阶段会更偏好收集这样的区域。

回收步骤

  • Pre Evacuate Collection Set 断开应用线程的TLAB,选出要收集的区域,从CSet中,以及其他的准备工作
  • Merge Heap Roots 合并Root,创建一个统一的Rset,把要收集的region中的Rset进行合并,如果不合并后面并行的时候要花费更大的代价来过滤
  • Evacuate Collection Set 递归内部引用,不断把活着的对象拷贝出去,
  • Post Evacuate Collection Set 处理引用,恢复用户线程。