你们线上用的是什么垃圾收集器?G1的GC生命周期了解吗?

简介: 不知道大家在平常工作中有没有观察过自己公司线上项目用的是什么垃圾收集器,项目的JVM参数都是怎么配置的?

01提出问题




从强哥面试过的许多候选人来看,很多小伙伴现在都比较注重技术的招式,而对技术的内功修炼的都比较差。


拿之前有一个候选人的例子来说,在前面的项目技术交流中都回答的不错,可是在问到Java基础,垃圾收集器,JVM调优时,就开始语塞,模棱两可。尤其令强哥惊讶的是,在问到他们公司线上配置的是什么垃圾收集器的时候,居然连垃圾收集器具体指的是什么都不知道……一下子把强哥先前对他的好印象惊到了九霄云外。


所以还是希望大家在追求新技术的同时,底层内功也不能落下。


言归正传,从Java发展到现在而言,一般的公司都用上了Java8。然而大家是否知道Java8的默认垃圾收集器是什么呢?查看Java的默认垃圾收集器可以用如下命令:


java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4294967296-XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers-XX:+UseCompressedOops -XX:+UseParallelGC java version "1.8.0_221"Java(TM) SE Runtime Environment (build 1.8.0_221-b11)Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode)


可以看出Java8的GC情况是:-XX:+UseParallelGC,即Parallel Scavenge(新生代) + Parallel Old(老生代)。


不过我们今天要讲的不是ParallelGC,而是Java9默认的垃圾收集器G1。相信很多公司在使用Java8的时候,也会将线上的垃圾收集器切换到G1。而在Java11  ZGC还没非常普及之前,多了解一些G1相关的知识对大家还是比较有好处的。


02G1生命周期


今天强哥就和大家讲讲G1收集器GC的生命周期过程。其实,用一张比较经典的图就可以表达出来,如下:


7.png


一定要详细看这张图下面的图标注释。然后对应到上面的生命周期图中。


从图中我们可以看到,G1垃圾收集主要包含三个Cycle:Young Collection Cycle、Concurrent Marking Cycle、Mixed Collection Cycle。在项目运行的过程中,会根据JVM堆内存情况,触发不同的过程。


  1. 正常情况下,在项目运行过程中,当老年代没有达到IHOP的时候,都是进行年轻代的垃圾收集,如图中IHOP Trigger箭头前的运行过程。
  2. 当堆内存情况符合IHOP Trigger的时候,在下一次Young GC时会触发Concurrent Marking Cycle。
  3. 当Concurrent Marking Cycle完成后,下一次Young GC时会触发多次Mixed Collection Cycle。


简单的来说就是三件的三个阶段,下面我们来具体的详细说明下:


Young Garbage Collections


年轻代收集集合 CSet of Young Collection:应用线程不断活动后,年轻代空间会被逐渐填满。当JVM分配对象到Eden区域失败(Eden区已满)时,便会触发一次STW式的年轻代收集。在年轻代收集中,Eden分区存活的对象将被拷贝到Survivor分区;原有Survivor分区存活的对象,将根据任期阈值(tenuring threshold)分别晋升到PLAB中,新的survivor分区和老年代分区。而原有的年轻代分区将被整体回收掉。


同时,年轻代收集还负责维护对象的年龄(存活次数),辅助判断老化(tenuring)对象晋升的时候是到Survivor分区还是到老年代分区。年轻代收集首先先将晋升对象尺寸总和、对象年龄信息维护到年龄表中,再根据年龄表、Survivor尺寸、Survivor填充容量-XX:TargetSurvivorRatio(默认50%)、最大任期阈值-XX:MaxTenuringThreshold(默认15),计算出一个恰当的任期阈值,凡是超过任期阈值的对象都会被晋升到老年代。


Concurrent Marking Cycle( 并不是每一次GC都会执行,只有达到IHOP等情况时会出发)


并发标记周期是G1中非常重要的阶段,这个阶段将会为混合收集周期识别垃圾最多的老年代分区。整个周期完成根标记、识别所有(可能)存活对象,并计算每个分区的活跃度,从而确定GC效率等级。


当达到IHOP阈值-XX:InitiatingHeapOccupancyPercent(老年代占整堆比,默认45%)时,便会触发并发标记周期。整个并发标记周期将由初始标记(Initial Mark)、根分区扫描(Root Region Scanning)、并发标记(Concurrent Marking)、重新标记(Remark)、清除(Cleanup)几个阶段组成。


其中,初始标记(随年轻代收集一起活动)、重新标记、清除是STW的,而并发标记如果来不及标记存活对象,则可能在并发标记过程中,G1又触发了几次年轻代收集。


Mixed Collection Cycle(混合收集集合)


mixed GC阶段是G1特有的,我们先来看段英文解释:


Upon successful completion of a concurrent marking cycle, the G1 GC switches from performing young garbage collections to performing mixed garbage collections. In a mixed garbage collection, the G1 GC optionally adds some old regions to the set of eden and survivor regions that will be collected. The exact number of old regions added is controlled by a number of flags that will be discussed later (see "Taming Mixed GCs"). After the G1 GC collects a sufficient number of old regions (over multiple mixed garbage collections), G1 reverts to performing young garbage collections until the next marking cycle completes.

可知,在完成了 Concurrent Marking Cycle阶段后,JVM会将Young GC切换到Mixed GC。


混合收集集合 CSet of Mixed Collection:年轻代收集不断活动后,老年代的空间也会被逐渐填充。当老年代占用空间超过整堆比IHOP阈值-XX:InitiatingHeapOccupancyPercent(默认45%)时,G1就会启动一次混合垃圾收集周期。为了满足暂停目标,G1可能不能一口气将所有的候选分区收集掉,因此G1可能会产生连续多次的混合收集与应用线程交替执行,每次STW的混合收集与年轻代收集过程相类似。


为了确定包含到年轻代收集集合CSet的老年代分区,JVM通过参数混合周期的最大总次数-XX:G1MixedGCCountTarget(默认8)、堆废物百分比-XX:G1HeapWastePercent(默认5%)。通过候选老年代分区总数与混合周期最大总次数,确定每次包含到CSet的最小分区数量;根据堆废物百分比,当收集达到参数时,不再启动新的混合收集。而每次添加到CSet的分区,则通过计算得到的GC效率进行安排。


年轻代收集和混合收集周期的切换


年轻代收集和混合收集周期,是G1回收空间的主要活动。当应用运行开始时,堆内存可用空间还比较大,只会在年轻代满时,触发年轻代收集;随着老年代内存增长,当到达IHOP阈值-XX:InitiatingHeapOccupancyPercent(老年代占整堆比,默认45%)时,G1开始着手准备收集老年代空间。首先经历并发标记周期,识别出高收益的老年代分区,前文已述。但随后G1并不会马上开始一次混合收集,而是让应用线程先运行一段时间,等待触发一次年轻代收集。在这次STW中,G1将保准整理混合收集周期。接着再次让应用线程运行,当接下来的几次年轻代收集时,将会有老年代分区加入到CSet中,即触发混合收集,这些连续多次的混合收集称为混合收集周期(Mixed Collection Cycle)。


什么时候发生Mixed GC呢?其实是由一些参数控制着的,另外也控制着哪些老年代Region会被选入CSet。* G1HeapWastePercent:在global concurrent marking结束之后,我们可以知道old gen regions中有多少空间要被回收,在每次YGC之后和再次发生Mixed GC之前,会检查垃圾占比是否达到此参数,只有达到了,下次才会发生Mixed GC。* G1MixedGCLiveThresholdPercent:old generation region中的存活对象的占比,只有在此参数之下,才会被选入CSet。* G1MixedGCCountTarget:一次global concurrent marking之后,最多执行Mixed GC的次数。* G1OldCSetRegionThresholdPercent:一次Mixed GC中能被选入CSet的最多old generation region数量。


除了以上的参数,G1 GC相关的其他主要的参数有:


参数 含义
-XX:G1HeapRegionSize=n 设置Region大小,并非最终值
-XX:MaxGCPauseMillis 设置G1收集过程目标时间,默认值200ms,不是硬性条件
-XX:G1NewSizePercent 新生代最小值,默认值5%
-XX:G1MaxNewSizePercent 新生代最大值,默认值60%
-XX:ParallelGCThreads STW期间,并行GC线程数
-XX:ConcGCThreads=n 并发标记阶段,并行执行的线程数
-XX:InitiatingHeapOccupancyPercent 设置触发标记周期的 Java 堆占用率阈值。默认值是45%。这里的java堆占比指的是non_young_capacity_bytes,包括old+humongous

好啦,G1的GC生命周期过程就介绍到这啦,还是那就话,很重要,望时长打开多看几遍会议巩固。


不羡招式,勤修内功,加油~共勉!

相关文章
|
6月前
|
算法 Java 程序员
【GC的过程】
【GC的过程】
|
3月前
|
存储 监控 算法
垃圾回收器、垃圾回收算法、空间分配担保、JVM调优、GC回收对象的过程
垃圾回收器、垃圾回收算法、空间分配担保、JVM调优、GC回收对象的过程
|
1月前
|
存储 缓存 算法
五、垃圾收集基础
五、垃圾收集基础
31 3
|
7月前
|
缓存 算法 Java
GC 的三种基本实现方式
GC 的三种基本实现方式
80 1
|
9月前
|
存储 算法 Java
JVM学习日志(十三) G1垃圾回收流程 及 垃圾回收器总结
G1垃圾回收流程 及 垃圾回收器 总结 简述
154 0
JVM学习日志(十三) G1垃圾回收流程 及 垃圾回收器总结
|
7月前
|
机器学习/深度学习 算法 Java
大牛用十年功力带你彻底理解JVM垃圾回收器:ZGC,回收设计
ZGC的并发回收算法采用的也是“目的空间不变性”的设计,关于目的空间不变性的更多内容可以参考第7章。 在第7章中提到,Shenandoah从JDK 13开始也采用“目的空间不变性”的设计。但是ZGC与Shenandoah相比,还是有不少细节并不相同,如表8-3所示。
|
8月前
|
缓存 算法 Java
透彻理解JVM中垃圾回收GC生产参数,停顿时间+执行效率相关参数
停顿时间相关参数 部分垃圾回收器实现了GC执行时应用最大停顿时间的功能,所以提供参数用于应用控制停顿时间。另外,GC为了满足停顿时间,会设计和实现一些动态算法来调整堆空间,从而满足停顿时间这个目标。本节介绍相关参数。 该参数表示GC的最大的停顿时间。不同GC对于该参数的行为不一致,具体来说: 1)若Parallel GC中GC执行的时间超过该值,将导致调整新生代和老生代的大小(参数UseAdaptiveSizePolicy设置为true)。参数的默认值为4294 967 295,大约为50天(所以通常不会触发这个调整策略)。 2)若G1中GC执行的时间超过该值,将导致调整新生代的大小和
|
9月前
|
数据可视化 Java 应用服务中间件
GC 分析
GC 分析
74 0
|
10月前
|
Java
JVM GC频繁优化
JVM GC频繁优化
164 0
|
11月前
|
存储 SQL 算法
彻底理解对象内存分配及Minor GC和Full GC全过程
某数据计算系统,日处理亿级数据量。系统不断从各种数据源提读数据,加载到JVM内存进行计算处理
190 0