G1原理—4.G1垃圾回收的过程之Young GC

news/2025/1/11 20:28:41/文章来源:https://www.cnblogs.com/mjunz/p/18666171

大纲

1.G1的YGC过程

2.YGC并行处理阶段的过程

3.YGC串行处理阶段的过程(一)

4.YGC串行处理阶段的过程(二)

5.整个YGC的执行流程总结

 

1.G1的YGC过程

(1)YGC相关的一些参数

(2)YGC和MixedGC、FGC之间的关系

(3)YGC使用的算法 + 新生代的垃圾回收流程

 

(1)YGC相关的一些参数

一.-XX:+UseG1GC

设置使用G1垃圾回收器。

 

二.-XX:G1HeapRegionSize

设置Region分区大小,最小值1M,最大值32M,且只能是2的n次幂。

 

三.-Xms和-Xmx或者InitialHeapSize和MaxHeapSize

设置堆内存最大值最小值。

 

四.-XX:NewSize和-XX:MaxNewSize

设置新生代最小值和最大值。注意,在G1里这个最大值最小值其实是可以不设置的。G1会自动计算出一个值:从5%的Region数量开始,慢慢增加到最大为60%的Region数量。一般不用指定新生代的最大值和最小值,按照默认的5%~60%即可。

 

五.新生代Region数量

下限-XX:G1NewSizeRercent,默认5%

上限-XX:G1MaxNewSizePercent,默认60%

 

六.新生代Eden和Survivor的比例:-XX:SurvivorRatio=n

默认为8,即eden : s1 : s2 = 8 : 1 : 1。这个比例和ParNew的原理是一致的,比如总的新生代是100个Region,那么Eden区有80个,两个S区各有10个。

 

七.-XX:MaxGCPauseMills=n

设置最大GC暂停时间,这是一个大概值,JVM会尽可能的满足此值。例如设置200ms,那么G1就会在每次GC时努力保证GC的停顿时间在这个范围内。

 

八.-XX:NewRatio=n

新生代与老年代的大小比例,默认值2。只设置一个NewRatio,与只设置一个Xmn是相当的。最好不要设置一个Xmn,或者最好不要单独设置一个NewRatio。因为这样会固定新生代大小,不利于停顿时间预测。

 

九.-XX:ParallelGCThreads=n

参与回收的线程数量,默认和CPU核数相等。

 

(2)YGC和Mixed GC、FGC之间的关系

G1中的YGC、Mixed GC以及FGC和ParNew + CMS是有相似之处的。比如,在新生代GC后,会有存活对象进入老年代。如果老年代对象占用达到了某个阈值,就会触发老年代的回收。在ParNew + CMS中,是直接触发FGC,而在G1中是触发Mixed GC。

 

在G1中首先会进行YGC,YGC会选择所有新生代的分区进行回收。当程序不断运行,存活对象越来越多,老年代的对象越来越多时,就会在某次YGC的时候,触发一个并发标记过程。

 

然后等待YGC和这次并发标记过程结束后,就会正式进入Mixed GC。Mixed GC会从老年代中选择部分回收价值比较高的Region进行回收,从而满足用户设置的MaxGCPauseMills值,当然Mixed GC也会回收所有新生代分区。当Mixed GC后,对象还是无法分配成功时,就会触发FGC。FGC会暂停程序运行,对整个堆进行全面的垃圾回收。FGC的回收会包括新生代、老年代、大对象等。

 

YGC、Mixed GC、FGC间的过程转换关系如下:

(3)YGC使用的算法 + 新生代的垃圾回收流程

一.不均匀的分区分布

二.对象在Eden区的分布

三.Eden区占满时触发YGC

四.标记存活对象

五.复制存活对象到Survivor区

六.回收垃圾对象

七.动态调整新生代区域Region数量

八.是否需要开启并发标记

九.新生代的垃圾回收流程结束

 

YGC使用的算法是复制算法,也就是会把新生代的所有Region按照Eden、Survivor做类型标识。在执行垃圾回收时,首先对存活对象进行标记。然后把存活对象复制到S区,接着就把所有的垃圾对象全部回收掉。注意:G1的Region分布,对于一个分代而言,不一定是连续的。

 

一.不均匀的分区分布

二.对象在Eden区的分布

三.Eden区占满时触发YGC

四.标记存活对象

首先从GC Roots出发,标记直接引用的对象,然后再一个一个标记GC Roots间接引用的对象。

五.复制存活对象到Survivor区

六.回收垃圾对象

如果是ParNew + CMS的新生代回收,其实到这里就基本上是结束了。

七.动态调整新生代区域Region数量

YGC回收掉的那些Region,是有可能会成为自由分区的。因为YGC回收后会动态判断,如果需要更多的Region就进行增加。如果回收时间太长,发现YGC下一次可能没有那么强的能力,那么G1就会减少几个Region。

 

八.是否需要开启并发标记

如果老年代的使用率达到了阈值,就开启并发标记。

 

九.新生代的垃圾回收流程结束

以上就是G1新生代垃圾回收的基本流程。

 

(4)总结

G1的YGC过程:

一.YGC相关的一些参数

二.YGC和MixedGC、FGC是什么关系

三.YGC使用的算法 + 新生代的垃圾回收流程

1.不均匀的分区分布

2.对象在Eden区的分布

3.Eden区占满时触发YGC

4.标记存活对象

5.复制存活对象到Survivor区

6.回收垃圾对象

7.动态调整新生代区域Region数量

8.是否需要开启并发标记

9.新生代的垃圾回收流程结束

 

2.YGC并行处理阶段的过程

(1)YGC的并行处理是什么

(2)GC Roots并行标记及RSet并行更新

(3)YGC并行标记阶段不仅会标记还会复制

(4)完成初始标记后的处理——将直接引用的对象的字段入栈

(5)遍历栈中的字段找出存活对象并复制到S区然后清理对象 + 清空栈

 

YGC有并行处理的过程以及串行处理的过程。

 

(1)YGC的并行处理是什么

YGC的过程,肯定是要做一些并行化处理的,否则速度就会比较慢。比如,标记对象时就不能一个一个对象去查找标记。所以,会有线程对GC Roots直接引用的对象进行标记。

 

(2)GC Roots并行标记及RSet并行更新

不仅在对GC Roots引用的对象进行标记时,会使用并行处理的方式。在对RSet进行更新时,也会用并行处理的方式。

 

G1在进行YGC时:会从RSet和GC Roots出发遍历所有新生代对象,然后标记存活对象。由于RSet的更新不一定会在YGC前就更新完毕,所以在YGC并行处理这个阶段,还要对RSet做并行处理的更新。即把DCQS里还没处理完毕的跨代引用关系变更,更新到RSet里面。

更新RSet完成后,再从RSet出发,去标记被RSet指向的老年代空间里的对象直接引用的新生代对象。

整个标记GC Roots + 更新RSet的过程,是由多个线程一起并行处理的。比如现在有4个GC线程参与垃圾回收,那么就会有两个线程从GC Roots出发去标记对象,有两个线程去消费DCQS然后更新RSet。接着Rset更新完毕后,就把RSet作为GC Roots继续去执行对象标记工作。

 

(3)YGC并行标记阶段不仅会标记还会复制

在YGC的并行标记阶段,不仅仅会根据GC Roots + RSet来追踪所有直接引用的对象。由于在执行YGC的过程中,复制操作和标记操作是同时进行的。所以在用GC Roots标记直接引用的存活对象时,也会进行复制操作。比如发现4个对象是由GC Roots直接引用的。

此时通过GC Roots找到这4个对象后,就会复制它们到一个Survivor区。

所以YGC里的复制算法,并不是等待全部标记完成,再去复制对象。而是找到一个直接引用的存活对象,就会复制到Survivor里了。

 

另外,把RSet作为GC Roots的意思是:RSet中映射到卡表对应的卡页中的所有对象都会作为GC Roots。因为卡页本身很小,对象数量也很少,所以可以把RSet都作为GC Roots。然后找到这些GC Roots直接引用的对象,再复制到Survivor区。

 

(4)完成初始标记后的处理——将直接引用的对象的字段入栈

仅仅处理这些GC Roots直接引用的对象还是不够的,因为还有很多对象会被它们间接引用。间接引用的对象,也需要全部找到并进行标记。

 

那么在并行处理阶段,GC线程还需要做的另外一件事就是:把刚刚找到的被GC Roots直接引用的哪些对象的字段Field,全部都给放入一个栈里面。

 

为什么要这么做?因为要把这些对象引用的所有对象都找到才行,找到它们引用的对象才能找到所有存活的对象。所以在把GC Roots + RSet直接引用的对象复制到S区时,就会把它们的所有字段放入一个栈中。

(5)遍历栈中的字段找出存活对象并复制到S区然后清理对象 + 清空栈

等到所有的GC Roots + RSet直接引用的对象都复制完毕后,再逐一对栈中的字段Feild进行遍历,找到所有存活的对象,然后再把找到的存活对象放入Survivor区中。

最后一口气回收掉所有的垃圾对象。

此时栈就会被清空掉了。

至此,YGC的并行操作基本已经结束,基本上YGC其实已经结束了。但是,实际上还会有后续的很多操作。比如以下操作就是在YGC的串行执行过程中需要做的,需要更新RSet、RSet卡表、释放被回收垃圾占用的Region、动态调整新生代分区数量来实现停顿预测模型等。

 

(6)总结

YGC并行处理阶段的过程:

一.YGC的并行处理是什么

二.GC Roots并行标记及RSet并行更新

三.YGC并行标记阶段不仅会标记还会复制

四.完成初始标记后的处理——将直接引用的对象的字段入栈

 

YGC的并行处理阶段具体会做的事情:

一.并行更新RSet

二.将更新完RSet加入GC Roots进行并行标记

三.并行复制直接引用的存活对象进入S区

四.将直接引用的存活对象的所有字段入栈

五.遍历栈的所有字段寻找所有存活对象

六.复制所有存活对象进入S区

七.清空全部垃圾对象

八.清空栈里的所有字段

 

3.YGC串行处理阶段的过程(一)

(1)YGC中的串行处理是什么

(2)YGC中的串行处理操作有哪些

一.软引用、弱引用、虚引用的处理

二.整理卡表

三.Redirty操作——清理旧RSet建立新RSet

四.释放分区

 

(1)YGC中的串行处理是什么

所谓串行处理,就是要一步步操作,否则就可能会出现错乱的一些操作。JVM会对垃圾回收中的一些操作使用串行化的处理方式。可能因为这些操作会有前后影响、或消耗的时间很少,所以才用串行化。当然不排除JVM后面可能会把这些操作优化成并行化的处理方式。

 

其中G1中的GC Roots追踪、RSet更新,这两个操作是可以并行进行的,因为这两个操作基本上不会出现互相影响的情况。但是YGC的其他一些操作,是有可能会出现先后影响的。

 

(2)YGC中的串行处理操作有哪些

一.软引用、弱引用、虚引用的处理

该操作是把这些引用中使用的存活对象也复制到新分区,否则就会出错。YGC中的并发处理阶段针对的是强引用对象。

 

软引用的回收时机:在第一次FGC时,是不回收软引用的。只有在第二次Full GC时,才会回收软引用。

 

在YGC执行串行处理操作时:就会把新生代里被这类引用给引用到的对象复制到Survivor区中。

二.整理卡表

卡表是一个全局卡表。在新生代在回收后,有些对象已被回收清除了,有些对象已经换了位置。这时就要把卡表中这些对象的描述数据也给清除掉和更新掉。

 

因为卡表中是一个字节描述512字节的内存空间。如果某内存空间被清除了,那么卡表的描述数据也需清空,否则会出错。

 

所以整理卡表的操作就是把已清理过的Region对应的卡表进行清空,同时把对象复制后所在的Region对应的卡表也进行修改,从而保证卡表中的描述数据是正确的。整理卡表的这个过程是很快的。

三.Redirty操作——清理旧RSet建立新RSet

这一步的主要操作,其实就是重构一下Rset。在做完垃圾回收后,新生代对象因为复制,其地址已经发生变化了。那么老年代引用的新生代对象所在Region的RSet此时还没有修改,因此需要把这个旧的RSet进行清理,然后建立一个新生代对象所在的新Region的RSet。重构RSet的过程也是很快的。

 

四.释放分区

新生代GC,需要把所有的非Survivor区的新生代Region都给清理掉。此时它们还被标记为Eden,或者Survivor(原本就可能有一些垃圾对象)。清理后,需要把这些Region分区给释放掉,否则需要分区时可能不够用。释放分区就是清空这些分区的标记,然后把清空后的分区加入到自由分区列表。

 

(3)总结

YGC串行处理阶段的过程:

一.YGC中的串行处理是什么

二.YGC中的串行处理操作有哪些

1.软引用、弱引用、虚引用的处理

2.整理卡表

3.Redirty操作——清理旧RSet建立新RSet

4.释放分区

 

(4)问题

如果我们是G1的开发者,在上面的流程结束之后还需要做什么?G1本身的设计思路就是,要垃圾回收优先,要满足系统的停顿时间。那么在GC之后最重要的事情是什么呢?

 

一.停顿预测模型和Region数量分配有关;

二.RSet处理时是比较耗时的,GC开启时Refine线程就会暂停,由GC线程来继续执行后续的操作。那么对于这个RSet、DCQ、DCQS的处理,是否需要调整?

三.是否需要扩展内存?

 

4.YGC串行处理阶段的过程(二)

(1)尝试对大对象进行回收(性价比很高)

(2)尝试扩展内存

(3)调整新生代分区的数目及Refine线程阈值

(4)尝试启动并发标记

 

(1)尝试对大对象进行回收(性价比很高)

一.为什么要对大对象尝试进行回收操作

原因一:大对象本身占用很多空间的,最少也会占1/2的Region

假如大对象能够回收,就顺带把它回收掉,这样就能腾出一块非常可观的空间出来了。

 

原因二:大对象回收起来不麻烦

因为大对象创建时是单独存储在一个分区(多个分区)的,属于单独存储。

 

二.如何判断大对象是否存活

由于每个Region都维护了一个RSet,并且RSet里存储的是引用关系信息。那么在YGC的串行处理阶段查看大对象所在Region的RSet,就能知道是否有其他对象在引用了。

 

注意大对象所在的Region的RSet不会有很多内容,最多就是两个对象被引用的关系。

 

所以如果大对象没有横跨多个分区,则只需判断一下大对象所在的Region的RSet里是否有内容,就可以判断大对象是否存活了。

 

如果大对象横跨多个分区,那么直接判断大对象所在的第一个Region的RSet里是否有内容,就可以知道大对象是否被引用了。

 

通过简单的判断就可能回收大量的空间,性价比非常高。所以要在YGC的串行处理阶段尝试一下对大对象进行回收。

 

(2)尝试扩展内存

前面介绍新生代内存时,介绍过可能会对新生代内存进行扩展,在YGC的串行处理阶段尝试扩展内存就是扩展新生代内存的时机之一。

 

完成YGC后会统计一下执行这次YGC的花费时间,而且还会统计一下在执行YGC前的系统运行总时间。于是就可以判断,这次YGC执行时间和系统运行总时间的比例是否合理。如果不合理,就要考虑扩展一下新生代内存,如果合理就没必要扩展了。

 

对应的参数是:GCTimeRatio和G1ExpandByPercentOfAvailable。其中GCTimeRatio是指:程序运行时间与YGC时间的比例。如果YGC时间占程序运行时间比例超过10%,就说明要扩展新生代内存。

 

为什么YGC时间占程序运行时间的比例超过10%就要扩展新生代内存?因为YGC时间占比超过10%,就说明要么YGC频繁、要么YGC时间太长。如果新生代空间足够大,加上G1会自己动态调整新生代分区的数量,那么就是YGC太频繁导致YGC的时间占程序运行时间比例超过10%。

 

YGC过于频繁,必然会导致判断出大量对象存活,相当于变相拖慢YGC。YGC中真正耗时的不是清理大量垃圾对象的过程,而是进行标记的过程。YGC中存活对象越多,进行标记的过程就越长。YGC越频繁 -> 说明新生代很快满了 -> 说明新生代需要扩展内存

 

如果YGC时间占程序运行时间的比例没有超过10%,则暂时不需要扩展,扩展的内存大小和G1ExpandByPercentOfAvailable有关。

 

(3)调整新生代分区的数目及Refine线程阈值

一.调整新生代分区数目

这个是YGC串行处理阶段的一个重点,因为对于G1来说,控制停顿时间是非常重要的。

 

要想控制好停顿时间:只能在系统运行时间和YGC过程中各个步骤的耗时上进行综合考量。综合考量后还要进行动态调整,这样才能保证停顿时间是可以被满足的。

 

那么在YGC后,首先就需要判断一下:现在的YGC耗时、YGC能力能否让下一次GC满足预期停顿时间。如果不能的话,那么就需要把新生代分区减少一些,不然就满足不了了。如果远远没达到停顿预测时间的阈值,那么就可以增加一些新生代分区。

 

所以这一步,就会根据当前YGC的执行时间和目标停顿时间,进行预测。看下一次YGC最多能回收多少分区,然后和当前新生代的总分区数对比。如果下次最多能回收的分区和当前新生代总分区数差不多,则无需调整。如果发现预测出来下一次YGC能回收1000个分区,而现在才600个分区。那么就可以多增加几个分区到新生代里,避免浪费堆内存。

 

二.调整RefinementZone的阈值

关于DCQS、DCQ和Refine线程的处理:如果DCQ比较多,则需要启动多个Refine线程去进行处理。而且在YGC开始时,这些Refine线程就会暂停,并且由YGC线程接管其工作来处理后续的DCQ。

 

如果YGC线程处理DCQ的时间过多,那么代表了什么?代表Refine线程的数量,或者DCQS的四个区域设置得不合理。如果设置合理,Refine线程在对应的区域中,就可满足DCQ消息的处理。此时YGC线程最多就是进行少部分的收尾工作,但现在YGC线程还需要大量的时间去处理DCQ消息,那么就说明:要么这几个DCQS的阈值设置得过大了、要么Refine线程太少了。

 

Refine线程理论上是不能在GC过程中动态调整上限的,所以我们只能调整DCQS的白绿黄红几个阈值的大小,通过白绿黄红来匹配Refine线程的处理能力。

 

比如把DCQS的各个阈值给降下来,然后把总长度也降下来。让系统线程也帮忙处理DCQ,这样就可以让GC线程的压力小一点。所以如果YGC处理DCQ时间过长,会导致DCQS的长度和阈值动态减小。

 

(4)尝试启动并发标记

这个过程也是一个尝试的过程。因为新生代的回收是一直在进行的,老年代的对象也是一直在累积的。

 

如果老年代对象累积到一定程度,那么此时就需要回收一部分老年代的垃圾对象,否则内存使用率就会太高。所以,在老年代达到45%的内存使用率时,一次YGC结束后就会开启一个并发标记过程。

 

如下图示:老年代占用内存达到阈值的判断,就是判断是否要进入MGC + YGC过程。如果成功启动了并发标记,就意味着接下来要进入Mixed GC了。

 

5.整个YGC的执行流程总结

YGC算法的流转过程:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/867894.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Matlab贝叶斯估计MCMC分析药物对不同种群生物生理指标数据评估可视化

全文链接:https://tecdat.cn/?p=38756 原文出处:拓端数据部落公众号 摘要:本文着重探讨了如何利用Matlab实现贝叶斯估计。阐述了具体的实现流程,涵盖数据加载、先验常数设定、马尔可夫链蒙特卡洛(MCMC)属性指定、模型构建、运行链条以及结果查看等环节,通过展示相应的代…

【专题】2024年电商报告汇总PDF洞察(附原数据表)

原文链接: https://tecdat.cn/?p=38770 在当今数字化浪潮汹涌澎湃的时代背景下,电商行业已然成为全球经济格局中极具影响力与活力的关键领域。 从中国电商市场的增长压力与结构变化,到各类促销活动背后的消费者行为逻辑;从不同平台内容创作者生态的差异化表现,再到跨境出…

Python、R用深度学习神经网络组合预测优化能源消费总量时间序列预测及ARIMA、xgboost对比

全文链接:https://tecdat.cn/?p=38726 原文出处:拓端数据部落公众号 分析师:Qingxia Wang 在能源领域,精准预测能源消费总量对制定合理能源战略至关重要。当前,能源消费预测分析主要运用单一模型(如灰色预测法、时间序列分析法等)和组合模型两种方式。然而,单一模型存…

Python深度学习GRU、LSTM 、BiLSTM-CNN神经网络空气质量指数AQI时间序列预测及机器学习分析

全文链接:https://tecdat.cn/?p=38742 原文出处:拓端数据部落公众号 分析师:Zhixiong Weng人们每时每刻都离不开氧,并通过吸入空气而获得氧。一个成年人每天需要吸入空气达6500升以获得足够的氧气,因此,被污染了的空气对人体健康有直接的影响,空气品质对人的影响更是至…

如何选择和使用专业的代码修改服务?

如果您不具备编程技能,或者项目复杂度较高,选择一家可靠的代码修改服务提供商是明智之举。 解决方案:评估需求:明确您需要修改的具体内容和期望达到的效果。 选择服务商:通过在线平台或口碑推荐寻找信誉良好的服务商。查看他们的案例和客户评价。 沟通需求:与服务商详细沟…

前端加密对抗-1

在实习的时候遇到很多的项目都使用了加密来保护安全性,测试起来非常的费劲;然后最近看到了有这么一个前端加密靶场,利用这个靶场来多学习学习这方面的知识。改包的防范 目前流行的防止改包方式主要是这么几个方面请求参数和路径的加密 如果原始请求是GET请求,或防止访问者获…

如何在CentOS云服务器上一键自动挂载磁盘?

对于新手来说,通过命令行手动挂载磁盘可能会有一定的难度。幸运的是,使用宝塔面板的一键挂载脚本可以简化这个过程。该脚本经过优化,直接绑定UUID以避免分区飘移问题,并能自动将硬盘挂载到/www目录。如果之前已经安装了宝塔面板,脚本会自动迁移数据到新的磁盘并挂载到/www…

WordPress需要在什么环境下运行?

WordPress 是一个基于 PHP 语言和 MySQL 数据库管理系统构建的开源内容管理系统(CMS)。为了确保 WordPress 网站能够稳定、高效地运行,您需要为其提供合适的运行环境。以下是详细的环境要求和建议: 一、WordPress 运行环境要求组件 推荐配置 说明Web服务器 Apache 或 Nginx…

网站SSL证书有什么用?什么情况下需要申请SSL证书?

网站SSL证书在保障网站安全和提升用户体验方面扮演着重要角色。以下是SSL证书的主要用途和申请需求的详细说明。 一、网站SSL证书的作用 1. 数据加密传输作用:SSL证书确保用户浏览器和服务器之间的数据传输是加密的,防止第三方窃取敏感信息,如登录密码、支付数据等。 重要性…

dedecms上传图片附件失败的原因和解决办法

dedecms上传图片附件失败可能是由于以下几个原因导致的:目录权限问题:检查网站目录权限是否可写(uploads目录或后台定义的上传目录)。 文件大小限制:检查上传图片大小是否超过php.ini中定义的大小。 子目录缺失:检查上传图片附件目录中的子目录是否存在,如allimg、flink…

独立IP虚拟主机相较于共享IP虚拟主机有哪些优势?

独立IP虚拟主机与传统共享IP虚拟主机相比,具有显著的优势。在共享IP环境中,多个网站共用一个IP地址,而独立IP虚拟主机为每个网站分配唯一的IP地址。以下是独立IP虚拟主机的主要优势: 1. 更高的稳定性资源独享:由于每个网站拥有独立的IP地址,因此不会受到其他网站的影响。…