JVM垃圾回收器详解(下)-G1收集器| 8月更文挑战

·  阅读 168

JVM垃圾回收器详解(上)-CMS收集器| 8月更文挑战

前言: 了解G1垃圾收集器之前需要先了解一下G1之前的垃圾收集器,如有不了解的,点击 JVM垃圾回收器详解(上)-CMS收集器| 8月更文挑战前往了解

G1收集器

G1(Garbage-First)收集器是在JDK1.7出现的,目的是想替代CMS收集器,是一款划时代的垃圾收集器,既承接了CMS收集器,也为后续的ZGC等收集器打下了基础G1。是一款针对服务器的垃圾收集器,主要针对配备多核处理器及大容量内存的机器. 以高可能性满足GC停顿时间要求的同时还能具备高吞吐量性能特征.

首先在G1中,不再按以前的将堆按比例划分为固定的Eden区,Survivol区,老年区。虽然G1取消了之前的

image.png

而是将堆划分为大小相等的独立区域,称作Region,Region最大数量为2048个,也就是2的十一次方,Region是G1的最小回收单位。虽然G1取消了之前的按比例划分为固定的Eden区,Survivol区,老年区。但是依然还是有新生代,老年代的概念,只是不在是固定的区域,他们可以是不连续的Region集合,而且Region区域是会变化,可能一个Region区域现在是年轻代,在经过几次GC后就变成了老年代区域,也就是说Region是会动态变化的。

G1有几个特别的地方:

  • 如年轻代的Region,默认占比堆内存为5%,但是随着程序的不断运行,G1会给Region不断的增加,扩大Region的区域,默认最大扩大为60%,这两个值都可以通过参数设置。
  • 大对象的处理:G1收集器相对于之前的收集器,多了个对大对象的处理,有专门存储大对象的Region叫做Humongous区,而不是像之前的收集器让大对象直接放入到老年代,在G1收集器中对大对象的判定就是一个大对象超过了一个Region大小的50%,比如每个Region是2M,只要一个对象超过了1M,那么就会被判定为大对象,就会被放入Humongous中,而且一个大对象如果太大,可能会横跨多个Region来存放,例如是4M的大对象,就会横跨两个Region存放。Humongous区专门用来存放短期巨型对象,不会直接进老年代,这样一来可以节约老年代的空间,避免因为老年代空间不够的产生Full GC来影响程序性能。另外在Full GC的时候除了回收年轻代和老年代之外,也会将Humongous区一起回收。

G1区域分配图:

image.png

G1垃圾回收步骤 G1收集器的垃圾回收步骤大致分为四个步骤:

  • 初始标记:初始标记是个速度很快的阶段,会暂停其他工作线程,记录下gc roots能直接引用的对象。
  • 并发标记:跟CMS并发标记一致
  • 最终标记:跟CMS最终标记步骤类似,区别为G1使用的SATB(Snapshot At The Beginning)原石快照。
  • 筛选回收:筛选回收阶段首先对各个Region的回收价值和时间进行排序,根据所设置的期望的GC停顿时间,在这个设置的停顿时间内进行最大层次的Region的回收,比如说现在老年代有100个Region都满了,然后根据预期停顿时间,本次垃圾回收可能需要停顿100ms,那么通过之前回收成本计算得知,可能回收其中80个Region刚好需要100ms,那么就只会回收这80个Region,以此达到设置的GC停顿时间。

G1垃圾回收步骤图:

image.png

Region优先列表 G1收集器在回收的后台维护了一个专门存放Region回收价值相关的优先列表,每次根据设置的停顿时间,优先选择回收价值最大的Region,比如一个Region花10ms能回收10M垃圾,另外一个Region花50ms能回收20M垃圾,那么在回收时间有限情况下,G1会优先选择前面这个Region进行回收。这种回收方式保证了G1收集器在最短的时间内可以有更高的回收效率。

垃圾回收算法: 标记-整理。

使用参数设置: -XX:+UseG1GC

其他参数设置:

  • -XX:G1HeapRegionSize:指定分区大小(1MB~32MB,且必须是2的N次幂),默认将整堆划分为2048个分区

  • -XX:MaxGCPauseMillis:目标暂停时间(默认200ms)

  • -XX:G1NewSizePercent:新生代内存初始空间(默认整堆5%)

  • -XX:G1MaxNewSizePercent:新生代内存最大空间

  • -XX:TargetSurvivorRatio:Survivor区的填充容量(默认50%),Survivor区域里的一批对象(年龄1+年龄2+年龄n的多个年龄对象)总和超过了Survivor区域的50%,此时就会把年龄n(含)以上的对象都放入老年代

  • -XX:MaxTenuringThreshold:最大年龄阈值(默认15)

G1的使用场景:

  1. 存活对象占堆内存的50%以上50%

  2. 对象分配和晋升的速度变化非常大

  3. GC时间超过1s

  4. 8GB以上的堆内存

  5. 期望停顿时间比较短,如500ms以内

总结:

毫无疑问,G1是一款非常优秀的垃圾回收期,特别是在JDK9开始后,G1是JVM默认的垃圾回收器,但是即使是G1也有着自己不足的地方,如虽然能支持大内存,如8G以上,单是到了上TB后的内存就不行了,这里就得推荐下ZGC了,有兴趣的伙伴可以去了解一下ZGC相关的知识。从Serial到G1的发展过程来看,以后的垃圾回收器肯定是越来越强,支持的内存与所能设置的停顿时间肯定是越来越短,甚至有可能能根据程序运行的过程中自动调优,让我们期待吧。 Q.E.D.

分类:
后端
标签: