23-一文带你搞懂G1收集器

简介: G1是一款主要面向服务端应用的垃圾收集器。 HotSpot开发团队最初赋予它的期望是(在比较长期的) 未来可以替换掉JDK 5中发布的CMS收集器。 现在这个期望目标已经实现过半了, JDK 9发布之日, G1宣告取代Parallel Scavenge加Parallel Old组合, 成为服务端模式下的默认垃圾收集器, 而CMS则沦落至被声明为不推荐使用(Deprecate) 的收集器 。
G1收集器介绍

Garbage First(简称G1) 收集器是垃圾收集器技术发展历史上的里程碑式的成果, 它开创了收集器面向局部收集的设计思路和基于Region的内存布局形式。 早在JDK 7刚刚确立项目目标、 Oracle公司制定的JDK 7 RoadMap里面, G1收集器就被视作JDK 7中HotSpot虚拟机的一项重要进化特征。

G1是一款主要面向服务端应用的垃圾收集器。 HotSpot开发团队最初赋予它的期望是(在比较长期的) 未来可以替换掉JDK 5中发布的CMS收集器。 现在这个期望目标已经实现过半了, JDK 9发布之日, G1宣告取代Parallel Scavenge加Parallel Old组合, 成为服务端模式下的默认垃圾收集器, 而CMS则沦落至被声明为不推荐使用(Deprecate) 的收集器 。

首先要有一个思想上的改变, 在G1收集器出现之前的所有其他收集器, 包括CMS在内, 垃圾收集的目标范围要么是整个新生代(Minor GC) , 要么就是整个老年代(Major GC) , 再要么就是整个Java堆(Full GC) 。 而G1跳出了这个樊笼, 它可以面向堆内存任何部分来组成回收集(Collection Set, 一般简称CSet) 进行回收, 衡量标准不再是它属于哪个分代, 而是哪块内存中存放的垃圾数量最多, 回收收益最大, 这就是G1收集器的Mixed GC模式。

G1开创的基于Region的堆内存布局是它能够实现这个目标的关键。 虽然G1也仍是遵循分代收集理论设计的, 但其堆内存的布局与其他收集器有非常明显的差异: G1不再坚持固定大小以及固定数量的分代区域划分, 而是把连续的Java堆划分为多个大小相等的独立区域(Region),每一个Region都可以根据需要, 扮演新生代的Eden空间、 Survivor空间, 或者老年代空间。 收集器能够对扮演不同角色的Region采用不同的策略去处理, 这样无论是新创建的对象还是已经存活了一段时间、 熬过多次收集的旧对象都能获取很好的收集效果。

Region中还有一类特殊的Humongous区域, 专门用来存储大对象。 G1认为只要大小超过了一个Region容量一半的对象即可判定为大对象。 每个Region的大小可以通过参数-XX: G1HeapRegionSize设定, 取值范围为1MB~32MB, 且应为2的N次幂。 而对于那些超过了整个Region容量的超级大对象,将会被存放在N个连续的Humongous Region之中, G1的大多数行为都把Humongous Region作为老年代的一部分来进行看待, 如下图所示:

虽然G1仍然保留新生代和老年代的概念, 但新生代和老年代不再是固定的了, 它们都是一系列区域(不需要连续) 的动态集合。 G1收集器之所以能建立可预测的停顿时间模型, 是因为它将Region作为单次回收的最小单元, 即每次收集到的内存空间都是Region大小的整数倍, 这样可以有计划地避免在整个Java堆中进行全区域的垃圾收集。

G1收集器能建立可预测的停顿时间模型 这句话什么意思?

比如我们希望G1在垃圾回收的时候可以保证1小时内系统停顿(STW)的时间不超过1分钟。

那这个模型就很厉害了!之前我们通过各种JVM参数设置,内存分配就是为了尽可能的减少Minor GC和Full GC带来的停顿,从而影响系统的请求。 而现在通过G1收集器能直接给定一个指定的时间,交给G1全权负责,达成目标!

那么G1是如何做到对垃圾回收导致的系统停顿可控的?

G1收集器之所以能建立可预测的停顿时间模型, 是因为它将Region作为单次回收的最小单元, 即每次收集到的内存空间都是Region大小的整数倍, 这样可以有计划地避免在整个Java堆中进行全区域的垃圾收集。

那么具体的思路是:G1会对每一个Region里回收价值进行追踪,动态的判断如何回收

啥叫回收价值呢?也就是G1必须搞清楚每一个Region里面到底有多少的垃圾对象需要回收,以及回收这些对象需要消耗多少时间。

比如下图,1个Region中有10MB,需要回收时间为1S,另一个Region中有20MB垃圾对象,需要消耗200ms,那么G1肯定会优先选择时间更少还能回收更多垃圾的200msRegion。

G1收集器去跟踪各个Region里面的垃圾堆积的“价值”大小, 价值即回收所获得的空间大小以及回收所需时间的经验值, 然后在后台维护一个优先级列表, 每次根据用户设定允许的收集停顿时间(使用参数-XX:MaxGCPauseMillis指定, 默认值是200毫秒) , 优先处理回收价值收益最大的那些Region, 这也就是“Garbage First”名字的由来。这种使用Region划分内存空间, 以及具有优先级的区域回收方式, 保证了G1收集器在有限的时间内获取尽可能高的收集效率。 这也是G1的核心设计思路。

相关JVM参数:

-XX:+UserG1GC :在JDK8中可以通过手动指定使用G1收集器进行回收

-XX: G1HeapRegionSize=size 指定每一个Region的大小

-XX:MaxGCPauseMillis=time 指定收集的停顿时间,默认是200ms

G1中的Region是如何分配的?每个Region大小是多少?

默认情况下是自己分配和设置,我们依然可以通过参数:“-Xms”和“-Xmx”来设置堆内存的大小,默认情况下是分配2048个Region,比如我们设置堆内存大小为2G,那么分配到2048个Region中,每一个Region的大小就是1MB。而且Region的大小必须是2的倍数,比如1MB,2MB,4MB之类的。

当然我们也可以通过“-XX:G1HeapRegionSize”来手动指定每一个Region的大小。

这里还有一些默认配置需要大家清楚:

  • 新生代默认开始分配占比是5%,可以通过“-XX:G1NewSizePercent“来设置新生代初始占比
  • 新生代运行过程中最多可以分配到60%的堆内存,可以通过“-XX:G1MaxNewSizePercent”来设置
  • 新生代中默认也是按照8:1:1对Eden和survivor去进行分配

下一篇将继续深入分析G1收集器的垃圾回收流程。

目录
相关文章
|
1天前
|
存储 算法 Java
深入浅出JVM(十八)之并发垃圾收集器G1
深入浅出JVM(十八)之并发垃圾收集器G1
|
1天前
|
存储 算法 Java
深入浅出JVM(十七)之并发垃圾收集器CMS
深入浅出JVM(十七)之并发垃圾收集器CMS
|
1天前
|
存储 算法 Java
深入浅出JVM(十二)之垃圾回收算法
深入浅出JVM(十二)之垃圾回收算法
|
3天前
|
Arthas 监控 算法
JVM工作原理与实战(二十五):堆的垃圾回收-垃圾回收算法
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了垃圾回收算法评价标准、标记清除算法、复制算法、标记整理算法、分代垃圾回收算法等内容。
15 0
JVM工作原理与实战(二十五):堆的垃圾回收-垃圾回收算法
|
4月前
|
算法 Java
jvm性能调优 - 09白话新生代垃圾回收算法
jvm性能调优 - 09白话新生代垃圾回收算法
31 0
|
9月前
|
监控 算法 Java
常问的GC相关面试题(二)
常问的GC相关面试题(二)
|
9月前
|
监控 算法 Java
常问的GC相关面试题(一)
常问的GC相关面试题(一)
|
9月前
|
算法 Java
马士兵2022版JVM G1GC纯手写学习笔记,精通JVM调优
今天不仅仅是给大家分享一份JVM的PDF,不仅仅是包含了一份PDF同时还有这套JVM的系统的学习视频,让大家彻底精通JVM!
|
10月前
|
缓存 监控 Java
一文搞懂 JVM GC 行为
在日常的 Java 虚拟机进行监控的时候,我们往往会观测到各种各样的图形,无论是基于 JDK 自带的 Jconsole、Jvisualvm、JMC 还是第三方工具或插件,例如,Jprofile 、GCeasy 等。基于对垃圾收集模式的监测,我们可以实时观摩应用程序的健康状态和性能特征,以方便为后续的性能调优提供数据参考。
91 0
|
11月前
|
存储 算法 Java
JVM原理:JVM垃圾回收算法(通俗易懂)
JVM原理:JVM垃圾回收算法(通俗易懂)
3857 0