G1收集器

G1收集器

G1(Garbage-First)收集器:是一款面向服务端应用的收集器,与其他收集器相比,具有以下特点:

  1. G1把内存划分成多个独立的区域(Region)(大概2000多块)
  2. G1采用(保留)分代思想,保留了新生代和老年代(逻辑概念上),但他们不再是物理隔离的,而是一部分Region的集合,且不需要Region是连续的。

G1把内存进行分块,杂乱无章的。

G1内存的分配

1.TLAB(TLAB占用年轻代内存). 默认使用TLAB加速内存分配,之前文章已经讲过,不赘述。

2.Eden.如果TLAB不够用,则在Eden中分配内存生成对象。

3.Humongous.如果对象需要的内存超过一个region的50%以上,会忽略前两个步骤直接在老年代的humongous中分配(连续的Region)

G1区域划分:

在G1中,还有一种特殊的区域,叫Humongous区域。 如果一个对象占用的空间超过了分区容量50%以上,G1收集器就认为这是一个巨型对象。这些巨型对象,默认直接会被分配在年老代,但是如果它是一个短期存在的巨型对象,就会对垃圾收集器造成负面影响。为了解决这个问题,G1划分了一个Humongous区,它用来专门存放巨型对象。如果一个H区装不下一个巨型对象,那么G1会寻找连续的H分区来存储。为了能找到连续的H区,有时候不得不启动Full GC。

PS:在java 8中,持久代也移动到了普通的堆内存空间中,改为元空间。

Humongous用来存储大对象的区域(对象占用空间超过一半),分配到老年代中。

G1能充分利用多CPU、多核环境硬件优势、尽量缩短STW

G1整体上采用标记-整理算法,局部是通过复制算法,不会产生内存碎片(基本上不会发生FullGC)

G1的停顿可预测,能明确指定在一个时间段内,消耗在垃圾收集上的时间不能超多多长时间

G1跟踪各个Region里面垃圾堆的价值大小,在后台维护一个优先列表,每次根据允许的时间来回收价值最大的区域,从而保证在有限时间内的高效收集(回收哪些块能够释放的区域最大,哪些块里面的垃圾最多)

跟CMS类似,也分为四个阶段:

初始标记:只标记 GC Roots 能直接关联到的对象

并发标记:进行 GC Roots Tracing的过程

最终标记:修正并发标记期间,因程序运行导致标记发生变化的那一部分对象

筛选回收:根据时间来进行价值最大化的回收

初始标记、最终标记、筛选回收 —-> 发生 STW 现象

G1收集器新生代回收过程

新生代:对新生代区域进行回收,1:Regioni区直接被回收 2 :还有用,拷贝到Survivor 区 3.还有一部分直接从Survivor拷贝到老年代

复制算法

G1收集器老年代的回收过程(麻烦一点) G1是Mix GC 混合垃圾回收

在初始标记阶段,老年代区域为空(会被干掉)

老年代

空闲区 Free Region

使用和配置G1:

-XX:+UseG1GC: 开启G1,默认是G1(JDK13)

-XX:MaxGCPauseMillis=n: 最大GC停顿时间,这是个软目标,JVM将尽可能(但不保证)地炖小于这个时间

-XX:InitiatingHeapOccupancyPercent=n: 堆占用了多少的时候就触发GC,默认为45%

–XX:NewRatio=n: 默认为2

–XX:SurvivorRatio=n: 默认为 8

–XX:MaxTenuringThreshold=n: 新生代到老年代的岁数,默认是 15

-XX:ParallelGCThreads=n: 并行GC的线程数,默认值会根据平台的不同而不同

-XX:ConcGCThreads=n: 并发GC使用的线程数

-XX:G1ReservePercent=n: 设置作为空闲空间的预留内存百分比,以降低目标空间溢出的风险,默认值是10%

-XX:G1HeapRegioniSize=n: 设置的G1区域的大小。值是2的幂,范围是1MB到32MB。目标是根据最小的Java堆大小划分出约2048个区域

---- The end of this article ----