JVM学习笔记24-G1垃圾收集器

G1收集器—Garbage First Collector
官方文档地址:点击访问

1 背景

  • 吞吐量
    吞吐量关注的是,在一个指定的时间内最大化一个应用的工作量
    如下方式来衡量一个系统吞吐量的好坏
    • 在一小时内同一个事务(或者任务, 请求)完成的次数(tps)
    • 数据库一小时可以完成多少次查询

对于关注吞吐量的系统,卡顿是可以接受的,因为这个系统关注长时间的大量任务的执行能力,单次快速的响应并不值得考虑

  • 响应能力
    响应能力—一个程序或者系统对请求是否能够及时响应,比如
    • 一个桌面UI能多块地响应一个事件
    • 一个网站能够多快返回查询的数据
    • 数据库能够多快的返回查询的数据

对于这列对相应能力敏感的场景,长时间的停顿是无法接受的


2 简介

  • G1收集器是一个面向服务端的垃圾收集器,适用于多核处理器,大内存容量的服务器
  • 它满足短时间GC停顿的同时达到一个较高的吞吐量
  • JDK 7以上版本适用

设计目标

  • 与应用线程同时工作,几乎不需要STW(与CMS类似)
  • 整理剩余空间,不产生内存碎片(CMS只能在Full GC时,用STW整理内存碎片)
  • GC停顿更加可控
  • 不牺牲系统的吞吐量
  • GC不要求额外的内存空间(CMS需要预留空间存储浮动垃圾)

设计规划—替换掉CMS
G1在某些方面弥补了CMS的不足,比如

  • CMS使用的是Mark-Sweep算法,自然会产生垃圾碎片
  • G1基于Copying算法,高效的整理剩余内存,而不要管理内存碎片

另外,G1提供多种手段,以达到对GC停顿时间的可控

  • Hotspot虚拟机的主要构成

JVM学习笔记24-G1垃圾收集器

3 G1收集器的堆结构

JVM学习笔记24-G1垃圾收集器

  • Heap被划分为一个个相等的不连续的内存区域(regions),每个region都有一个分代的角色
    • Eden
    • Survivor
    • Old
  • 对每个角色的数量并没有强制的规定,也就是说对每个分代内存的大小,可以动态变化
  • G1最大的特点就是高效的执行回收,优先去执行那些大对象可回收的区域(region)

G1使用了GC停顿时间可预测的模型来满足用户设定的GC停顿时间,根据用户设定的目标时间,G1会自动的选择哪些region要清除,一次清除多少个region

G1从多个region中复制存活的对象,然后集中放入到一个region, 同时清除, 整理内存(copying收集算法)


4 G1对比其他垃圾收集器

  • 对比使用Mark-Sweep的CMS, G1使用的copying算法不会造成内存碎片
  • 对比Parallel Scavenge(基于copying), Parallel Old收集器(基于Mark-Compact ),Parallel会对整个区域做整理导致GC停顿时间会比较长,而G1只是特定的整理几个region

G1并非一个实时的收集器, 与Parallel Scavenge一样, 对GC停顿时间的设置并不绝对生效, 只是G1有较高的几率保证不超过设定的GC停顿时间.

与之前的GC收集器对比,G1会根据用户设定的GC停顿时间,只能评估哪几个region需要被回收可以满足用户的设定


6 相关概念

6.1分区

  • 分区(Region)—G1采取了不同的策略来解决并行, 串行和CMS收集器的碎片, 暂停时间不可控等问题----G1将整个堆分成相同大小的分区(Region)

每个分区都可能是年轻代也可能是老年代, 但是同一时刻只能属于某个代

年轻代, 幸存区,老年代这些概念还存在,成为逻辑上的概念, 这样方便复用之前分代框架的逻辑

在物理上不需要连续,则带来了额外的好处—有些分区垃圾对象特别多,有的分区垃圾对象很少,G1会优先回收垃圾对象特别多的分区,这也就是G1名字的由来,及首先收集拉结最多的分区

依然是在新生带满了的时候,对这个新声带进行回收—整个新生代中的对象,要么被回收,要么被晋升,至于新生代也采取分区机制的原因,则是因为这样跟老年代的策略统一,方便调整代的大小

G1还是一种带压缩的收集器,在回收老年代的分区时,是将存活的对象从一个分区拷贝到另外一个分区,这个拷贝就实现了局部的压缩


6.2 收集集合CSet

一组可被回收分区的集合

在Cset中存活的数据会在GC过程中被移动到另一个可用分区
Cset中分区可以来自Eden空间, Survivor空间或者老年代

6.3 已记忆集合RSet

Rset记录了其他Region中的对象引用本Region中对象的关系,属于points-into结构(谁引用了我的对象)

Rset的价值在于使的垃圾收集器不需要扫描整个堆栈谁引用了当前分区中的对象,只需要扫描Rset即可

如下图所示
JVM学习笔记24-G1垃圾收集器
Region1和Region3中的对象都引用了Region2中的对象,一次在Region2的Reset中记录这两个引用

G1 GC是在points-out的card table之上再加了一层结构来构成points-into Rest—每个region会记录下到底哪些别的region有指向自己的指针,而这些指针分别在哪些card的范围内

这个Rest其实是一个hash table,key是别的region的起始地址,value是一个集合,里面的元素是card table的index.

举例来说,如果region A的Rset里有一项的key是region B,value理由index为1234的card
它的意思就是region B的一个card里有引用指向region A
所以对region A来说,该Rset记录的就是pints-into的关系;
而card table仍然记录points-out的关系

6.4 起始快照SATB(Snapshot-At-The_Beginning)

SATB是G1 GC在并发标记阶段使用的增量式的标记算法

并发标记是并发多线程的,但并发现在同一时刻只扫描一个Region

上一篇:垃圾收集器


下一篇:JVM垃圾收集器