Garbage First收集器

Garbage First收集器

  • G1是JDK9及以上版本中服务器端模式下的默认垃圾收集器

  • G1可以面向堆内存任何部分来组成回收集(Collection Set)进行回收,衡量标准不再是踏属于哪个分代,而是哪块内存中存放的垃圾数量最多,回收收益最大,这就是G1的Mixed GC模式

  • G1把堆分成多个大小相等的独立区域(Region),每个Region根据需要扮演Eden、Survivor、老年代空间。每个Region的大小可以通过-XX:G1HeapRegionSize设定,范围是1MB-32MB,且为2的N次幂

  • Region中还有一类特殊的Humongous区域,专门用来存储大对象。G1认为只要大小超过了一个Region容量一般的对象即可判定为大对象。对于超过了整个Region容量的超级大对象,将会被存放在N个连续的Humongous Region之中,G1大多数行为都把Humongous Region作为老年代的一部分看待

  • G1收集器去跟踪各个Region里面的垃圾堆积的“价值”大小,价值即回收所获得的空间大小以及回收所需时间的经验值,然后在后台维护一个优先级列表,每次根据用户设定允许的收集停顿时间(默认200毫秒)优先处理回收价值收益最大的那些Region

  • G1至少要耗费大约相当于Java堆容量10%~20%的额外内存来维持收集器工作

  • G1在整体上采用标记-整理算法,在Region之间采用标记-复制算法,所以G1运作期间不会产生内存空间碎片。

  • 跨Region引用对象问题

    • 每个Region都维护有自己的记忆集,这些记忆集会记录下别的Region指向自己的指针,并标记这些指针分别在哪些卡片的范围之内。

    • G1记忆集在存储结构上本质是一种哈希表,Key是别的Region的起始地址,Value是一个集合,里面存储的元素是卡表的索引号

  • 并发标记阶段的实现

    • G1通过原始快照算法(SATB)解决用户线程改变对象引用时,不打破原本对象图结构的问题

    • G1为每个Region设计了两个名为TAMS(Top at Mark Start)的指针,把Region中的一部分空间划分出来用于并发回收过程中的新对象分配,并发回收时新分配的对象地址都必须要在这两个指针位置上。G1收集器默认在这个地址以上的对象是被隐式标记过的,即默认他们是存活的,不纳入回收范围内。

    • 如果内存回收的速度赶不上内存分配的速度,G1收集器也要*冻结用户线程执行,导致Full GC而产生长时间的“STOP THE WORLD”

  • 建立可靠的停顿预测模型问题

    • G1收集器的停顿预测模型是以衰减均值为理论基础实现的,在垃圾收集过程中,G1收集器会记录每个Region的回收耗时,每个Region记忆集里的脏卡数量等各个可测量的步骤花费的成本,并分析得出平均值、标准偏差、置信度等统计信息。

    • 衰减平均值会比普通的平均值更容易受到新数据的影响。Region的统计状态越新越能决定其回收的价值。

G1收集器的收集过程

  • 初始标记:仅仅标记GC Roots能直接关联到的对象,并且修改TAMS指针的值。让下一阶段并发标记过程中,用户线程可以正确的在可用的Region中分配新对象。这个过程需要停顿线程,但是耗时很短,而且是借用Minor GC的时候同步完成的。

  • 并发标记:从GC Root开始对堆中对象进行可达性分析,递归扫描整个堆中的对象图,找出要回收的对象,耗时较长,和用户进程并发执行。

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

  • 筛选回收:更新Region的统计数据,对各个Region的回收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划,可以*选择任意多个Region构成回收集,然后把决定回收的那一部分Region的存活对象复制到空的Region中,再清理掉整个旧Region的全部空间。必须暂停用户线程,由多条收集线程并行完成

上一篇:STM32_从SystemInit、__main到main()


下一篇:JVM Garbage First(G1) 垃圾收集器 性能调优与实践