G1收集器采用了另一种分配堆的方法。 后面的图片逐步检查了G1系统。

G1堆结构

G1堆事一个内存区域被切分为多个相同大小的区域(regions)

Slide8.png

区域大小是在jvm一启动就被选择的。JVM通常会生成两千个区域,每个区域大小相同,在1到32MB之间

G1堆分配

事实上,这些区域被映射成Eden、Survivor和年老代

G1-Slide9.png

图片中的颜色显示了哪个区域与哪个角色相关联。 将活动对象从一个区域撤离(即复制或移动)到另一个区域。 区域被设计为并行或不停止其他应用程序线程的情况下并行垃圾收集。

如图所示,区域被分成Eden、Suivivor和年老代。此外还有第四种巨大区域。这些区域被设计成存放大于标准区域50%的对象。他们被一个连续集合区域进行存储。最后一种区域是堆未使用区域。

注意:在撰写本文时,尚未优化庞大对象的过程。因此应避免创建这种大小的对象。

G1年轻代

年轻代堆被分成了大概两千个区域,区域大小在1MB到32MB之间。蓝色区域存储年老代对象,绿色区域存储年轻代对象。

G1-Slide10.png

注意:这些区域不需要像旧的垃圾收集器一样是内存连续的

G1的一次Young GC

存活的对象撤离(移动或者拷贝)一个或者多个存活区域,如果年龄阈值满足,一些对象会被提升到年老代区域。

G1-Slide11.png

这是一次stop-the-world的暂停。Eden大小和survivor大小在下一次yongGC被计算。“计票”(accounting)信息被保存用来帮助计算这些区域的大小。诸如暂停时间目标之类的事情也要考虑在内。

这种方法使调整区域大小变得非常容易,可以根据需要增大或缩小区域。

G1的YoungGC结束

存活的对象已经“撤离”到survivor区域或者年老代区域。

G1-Slide12.png

最近提升对象用dark blue表示,survivor区域时绿色。

关于G1,总结如下:

  1. 堆是一整个内存被切分成区域
  2. 年轻代由一组不连续的区域组成,这使得改变区域大小非常容易
  3. 年轻代垃圾回收或者yong GC会stop-the-world,所有的应用线程都会被停止。(Young generation garbage collections, or young GCs, are stop the world events. All application threads are stopped for the operation.)
  4. 年轻的GC使用多个线程并行完成。
  5. 将活动对象复制到新的幸存者或较旧的地区。

G1年老代的垃圾收集

像CMS收集器一样,G1收集器被设计为用于旧对象的低暂停收集器。 下表描述了旧版本的G1收集阶段。

G1收集阶段-并发标记周期阶段

G1收集器在老年代上执行以下阶段。 请注意,某些阶段是年轻一代收集的一部分。

Phase Description
(1) 初始标记 (Stop the World Event) 这会stop-the-world。 对于G1来说, 它可以像普通young GC一样执行。标记survivor区域(root regions) ,因为这些区域可能引用了老年代对象。
(2) 根区域扫描 扫描survivor区域来获得年老代的参考(Scan survivor regions for references into the old generation),当程序在运行时会发生这种情况。这个阶段必须完成之后fullGC才能发生。
(3) 并发标记 在堆中查找活动对象,在应用运行时候发生,。这个阶段可以被Young GC打断。
(4) 重新标记(Stop the World Event) 完成堆中存活对象的标记。使用一个叫snapshot-at-the-beginning (SATB)的算法要比CMS用的算法要快的多。
(5) 清除 (Stop the World Event and Concurrent) 对活动对象进行计数(accounting)和并完全清空区域。 (停止世界)
清除RememberSet(RSet)。 (停止世界)
重置空区域并将他们返回到空闲列表。 (并发)
(*) Copying (Stop the World Event) 这些操作会stop-the-world 以保证活着的对象撤离到新的未使用的区域。该操作可以被记录为[GC pause(young)]。或者年轻、年老代区域被标记为[GC pause (mixed)].

G1老年代垃圾收集详解

在定义了阶段之后,让我们看一下,他们如何与G1收集器中的旧版本就行交互。

初始标记

初始标记对象,在年轻代被执行。在日志中被记录为GC pause (young)(inital-mark).

G1-Slide13.png

并发标记阶段

如果空的区域被找到,他们在重新标记阶段会被立即移除。并且,计数(acounting)信息会决定存活度计算结果。

G1-Slide14.png

重新标记

空区域被删除并回收,并且在这阶段会计算所有区域的区域存活度(Region liveness )。

G1-Slide15.png

拷贝/清除阶段

G1选择“存活度”(liveness)最低的区域,这些区域可以以最快速度被收集。这些区域在执行young GC时候被收集。在日志中被记录为[GC pause (mixed)]。所以年轻代和年老代可以被同时收集。

拷贝/清除阶段之后

选定的区域被收集且被压缩,在图中分别用深蓝色和深绿色所表示

G1-Slide17.png

G1年老代总结

总而言之,关于旧一代的G1垃圾回收,我们可以提出一些关键点:

  • 并发标记阶段
    • 活跃度信息是在应用线程运行的被并行计算的
    • 在活着的对象“撤离”时间段内,并且这些区域即将被回收,在这个时候定义活跃度信息。
  • 并发标记阶段
    • 使用SATB算法,该算法比CMS使用的算法快得多。
    • 完全为空的区域将被回收
  • 拷贝清理阶段
    • 年轻代年老代可以同时执行回收操作
    • 年老代区域基于它们的活跃度被选择是否回收

剩下的日志查看还没有翻译

原文

https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html