gc java g1_G1GC 概念与性能调优

本文来自OPPO互联网技术团队,转载请注名作者。同时欢迎关注我们的公众号:OPPO_tech,与你分享OPPO前沿互联网技术及活动。

本文不讨论 G1 底层数据结构与算法,从 G1 GC 行为上做简要介绍 G1 的过程

Garbage-First Garbage Collector 从官网的描述来看:

G1 is a generational, incremental, parallel, mostly concurrent, stop-the-world, and evacuating garbage collector which monitors pause-time goals in each of the stop-the-world pauses. Similar to other collectors, G1 splits the heap into (virtual) young and old generations. Space-reclamation efforts concentrate on the young generation where it is most efficient to do so, with occasional space-reclamation in the old generation.

从介绍可以加粗几个重点

分代

并发

STW

在每个STW阶段关注暂停时间目标

回收主要集中在最有效的young generation, old generation则没这么频繁

在G1中,为了提升吞吐量,有一些操作永远是(STW) stop-the-world 的。其他的一些要长期的,如全局标记这种要全堆进行的操作与应用程序并发进行。为了让空间回收的 STW 尽可能减少,G1并行的分步的递增进行空间回收。G1通过追踪此前应用行为和垃圾回收停顿的信息来构建一个与开销有关的模型(Pause Prediction Model)。它使用这些信息停顿期间可做的工作。举个例子,G1首先回收最高效的区域(也即垃圾最满的区域,因此称为垃圾—优先)。

G1把堆分成了n个大小相同的region

7a337b93127e22729588982928d9c57d.png

E 是 eden region

S 是 survivor region

O 是 old region

H 是 humongous (老年代可以是 humongous,可以看出,他可以跨越多个连续regions。直接分配到老年代,防止反复拷贝移动)

Java 9 以后开启的参数

自从 Java9 后,引入的统一的日志,也就是 Xlog 参数。下面是建议的 GCLog 参数:

-Xlog:gc*:file=your.log:tags,time,uptime,level:filecount=5,filesize=100

G1 的 GC 阶段

我们明白,调优的基本步骤就是

Measure 收集相关诊断信息 (例如收集详细的gclog,默认log level info 可以满足大部分情况)

Understand 理解发生了什么

Tune 调优

只有明白了GC内部发生了什么,才能针对性的对其进行调整。

下面通过一些正常的 GC log 来理解 GC 的三种方式 GC 做了什么。

Young Only Phase

先用张图来简单理解 Young GC 过程

垃圾回收的过程就是 Allocated->eden; eden -> survivor; survivor -> survivor; survivor -> old;

f7a30b27c8e66d8bbbc1402af01053f0.png

可以看到,这里有 eden,survivor,old 还有个 free region。

e1a2442133ae81b262cd81c410c1d4d6.png

橙色就是活着的对象

5823c28c8daa88d5593a85b98254edc3.png

G1会把橙色对象拷贝到free region

36a2057eb0859506d4b4e351145543dd.png

当拷贝完毕,free region 就会晋升为 survivor region,以前的 eden 就被释放了

如果 Young gc 中,花费了大量的时间

正常来说,大部分在 Young 的对象都不会存活很长时间

如果不符合这个规则 (大部分在 Young 的对象都不会存活很长时间),你可能需要调整一下 Young 区域占比。来降低 Young 对象的拷贝时间。

-XX:G1NewSizePercent (默认:5) Young region 最小值

-XX:G1MaxNewSizePercent (默认: 60) Young region 最大值

Mixed gc Phase

Mixed gc 会选取所有的 Young region + 收益高的若干个 Old region。

ea6f8450411883e73ff6024c72352ccb.png

6055fe755e594daeaf022b0c60bd9842.png

5a9b03ef4073b1f366f15b96fccdfed0.png

同样的,被回收的 region 就变回 free region 了

从上图可以了解到 Mixed gc 只能回收部分的老年代

G1 是如何选择要回收的 regions 的?

-XX:G1MaxNewSizePercent 与 Young 关联

-XX:MixedGCCountTarget 与 old 关联

-XX:MixedGCCountTarget默认是8,意味着要在8次以内回收完所有的 old region

换句话说,如果你有 800 个 old region, 那么一次 mixed gc 最大会回收 100 个 old region

G1 也可以被调整成不做这么多工作,也就是回收少点,浪费堆内存,导致更堆使用

-XX:G1MixedGCLiveThresholdPercent(默认:85)可能会提高堆使用率

-XX:G1HeapWastePercent (默认:5) 如果可回收低于这个值, 那么将不会启动Mixed gc

Full gc Phase

Full gc 是不应该发生的

先来看看 GC 周期

987ffc03776359fe31518d14a49c5e33.png

G1 有两个阶段,它会在这两个阶段往返,分别是 Young-only,Space Reclamation.

Young-only 包含一系列逐渐填满 old gen 的 gc

Space Reclamation G1 会递进地回收 old gen 的空间,同时也处理 Young region

图是来自 oracle 上对 gc 周期的描述,实心圆都表示一次 GC 停顿

蓝色 Young-only

黄色 标记过程的停顿

红色 Mixed gc 停顿

在几次gc后,old gen 的对象占有比超过了 InitiatingHeapOccupancyPercent,gc就会进入并发标记准备(concurrent mark)。

G1 在每一次 Young 回收中都会查找活对象(有引用的对象)

G1 在 old region 并发查找活对象

叫 concurrent marking

可能花费很长时间

不会停止 Java 应用

G1 没有活对象的引用信息是不能进行垃圾回收的

Mixed gc 依赖 concurrent mark

回到 full gc,从上面简单分析得出,full gc 发生是没有足够的 free region,如果堆是足够大的,Mixed gc 没有回收足够的 old region,或者 concurrent mark 没法及时完成,都可能会导致 full gc。

gc 日志

[gc,start ] GC(78) Pause Young (Normal) (G1 Evacuation Pause)

上面是连续几次GC的日志,可以对照着 gc 周期来看。为了方便排版,把时间相关的tag给精简掉了。

GC(78) 是一次普通的young gc,里面信息有各种 region 的变化

这里简单说一下 humongous 对象的处理

humongous 对象在G1中是被特殊对待的,G1 只决定它们是否生存,回收他们占用的空间,从不会移动它们

Young-Only 阶段,humongous regions 可能会被回收

Space-Reclamation,humongous regions 可能会被回收

GC(79) 开始进入并发阶段

GC(80) 完成了 Cleanup,紧接着一个 Prepare Mixed GC(81) 的垃圾收集,对应周期虚线右边的蓝实心圆

GC(82) 之后就是 Space Reclamation 阶段了,多个 Mixed GC 会进行

根据日志,可以简单看到每个步骤花费的时间,以及对应区域垃圾的回收情况,结合GC参数,可以定位出什么问题,针对性的调整参数。

吞吐量跟低延时是无法兼得的,低延时意味着GC工作会更加频繁,相对的,会占用应用的资源,吞吐量降低。需要大吞吐量,那么GC工作就会减少,相对的,每次回收的垃圾就会多,暂停时间就会增加,延时就会增加。-XX:MaxGCPauseMillis G1 会尽量满足这个参数设定的目标时间,通过此参数可以平衡应用需要的吞吐量以及延时。

最后

本文主要参考资料是官方的文章和文档,没涉及到复杂的内部实现,新版的JDK除了对G1进行了改良之外,还推出了几种新的。

Epsilon GC (no-op),无操作垃圾回收器,简单点就是不回收垃圾,等堆空间分配完了,jvm也就停止了

zgc 超大堆垃圾回收器,暂停不超过10ms,支持T级别的堆

Shenandoah 同样也是低延迟垃圾回收器

由于知识简陋,难免会有勘误,欢迎讨论。

参考资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值