解构G1三部曲(三) 停顿预测模型的原理

前言

现在让我们来讲解G1的停顿预测模型,最初我在G1的参数里面看到了置信参数这个GC参数也就是G1ConfidencePercent,在参考文档[1] 里面我们可以看到这个可以参数是我们对预测的总体置信度,即如果我们相信G1的预测是精准的,G1的行为会更激进,更加相信自己选择的Region进行回收,当这个参数比较小的时候,就意味着启示G1会选择更有把握的Region进行回收。那问题来了,是不是又要来一次调优?答案是不需要,我们会在衰减停顿预测模型里面讲为什么不需要。

然后这个是置信度就让我相信,G1的停顿预测模型是来自于统计概率理论,所谓概率就是知道原因预测结果,我们总要假定我们行为导致的概率分布,然后选择对应的分布模型来进行预测,所谓的分布是一种整体描述,描述的是整体的样本行为。最终我推导来推导去推导到正态分布上去了,但这个推导最后被我推翻,但我还是在这里放出来了我的推导过程,博君一笑。

衰减停顿模型

在《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》明确指出G1的停顿预测模型来自于衰减均值(Decaying Average):

在垃圾收集过程中,G1收集器会记录每个Region的回收耗时、每个Region记忆集里的脏卡数量等各个可测量的步骤花费的成本,并分析得出平均值、标准偏差、置信度等统计信息。这里强调的"衰减平均值"是指它会比普通的平均值更容易受到新数据的影响,平均值代表整体平均状态,但衰减平均值更准确地代表"最近的"平均状态。
换句话说,Region的统计状态越新越能决定其回收的价值。然后通过这些信息预测现在开始回收的话,由哪些Region组成回收集才可以在不超过期望停顿时间的约束下获得最高的收益。

现在来看这个问题也应该一句话结束了,但我并不满足这个停顿衰减均值,我并不想知道某某是什么,而是某某为什么可以用这个来做。我在想背后的理论基础所在,核心问题在于,我们该如何预测。

指数平滑

让我们想象这样一个场景,由于我家附近没有地铁,所以我选择开车上班,所以我到公司的时间并非一成不变,但是也相对稳定, 我的一周通勤记录就会如下所示:

  • 周一: 30分钟
  • 周二: 35分钟(早上偶然起晚了一会儿)
  • 周三: 32分钟
  • 周四: 31分钟
  • 周五: 33分钟

现在是周五晚上,我想预测下周一我的通勤时间,我们可以用周五为参考量,认为这是最晚的时间,最具备参考价值,但是周一我们只花了三十分钟,34分钟偶然性更大。那我们换一种思路来看,我们不妨取平均值,也就是将周一到周五的通勤时间累加除以5, (30+35+32+31+33) / 5 = 32.2, 这看起来有点科学了,这个计算的依据来自于周一到周五的在我们的预测中,权重一样,但其实直觉告诉我们最近的数据参考价值最大。

因此我们不妨引入假设,越远的数据参考价值越小,毕竟我们周围开地铁也是说不定的事情,也有可能我们所在的地区有重要的活动,这些事情的影响都体现在近期的数据上。我们应当赋予最近的数据最高的权重,然后随着数据的变旧,权重应当越来越小。

现在让我们来接着预测,我们基本上不会认为,我们的预测会一成不变,一成不变意味着我们的预测没有在学习,在意识到变化这个量,我们不妨引入预测误差这个这个变量,我们可以用误差来修正我们的预测值,类似于猜数游戏,会有人跟你说大了还是小了。因此我们的预测公式变形了为对明天的新预测 = 对今天的旧预测 + 对错误的修正,这个错误修正可以是整数也可以是负数。

人会天然的从环境中开始学习,因此一个聪明的系统应当根据上一次的错误来修正下次的行为,那我们完全信任上一次的错误会沿用到下一次嘛,也不见得,我们不妨这是一个权重,因此我们的公式可以变形为: 对明天的新预测 = α * (今天的实际) + (1-α) * (对今天的旧预测)。这样看起来有点歧义,我们不妨用数学公式看的更真切一点:

F_t+1 是对时间点 t+1 的预测(对明天的新预测)

Y_t 是在时间点 t 的实际值(今天的实际)

F_t 是对时间点 t 的预测(对今天的旧预测)
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> F t + 1 = α Y t + ( 1 − α ) F t F_{t+1} = \alpha Y_t + (1-\alpha) F_t </math>Ft+1=αYt+(1−α)Ft
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> F t + 1 = α Y t + α ( 1 − α ) Y t − 1 + α ( 1 − α ) 2 Y t − 2 + ⋯ F_{t+1} = \alpha Y_t + \alpha(1-\alpha) Y_{t-1} + \alpha(1-\alpha)^2 Y_{t-2} + \cdots </math>Ft+1=αYt+α(1−α)Yt−1+α(1−α)2Yt−2+⋯
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> F t + 1 = ∑ k = 0 ∞ α ( 1 − α ) k Y t − k F_{t+1} = \sum_{k=0}^{\infty} \alpha(1-\alpha)^k Y_{t-k} </math>Ft+1=k=0∑∞α(1−α)kYt−k

这个 α 还有在机器学习里面还有另外一个名字,也就是学习率,在时间序列分析中也被称为平滑系数。在参考资料[3] 可以确实看到G1采用了指数平滑来进行预测。

总结一下

本篇讲了停顿原理背后的原理,也就是我们该如何做预测,在什么样的场景该做什么样的预测,基于简单指数平滑理论的衰减均值强调的是最近的实际值会产生最大影响,但是也不忽略历史值,只是赋予比较低的权重。这也是本篇讲的指数平滑,我们本篇只讲了简单指数平滑

附记

下面是我错误的理解了G1的数学理论基础做出的错误推导,博读者诸君一笑。

基本数学原理概述

要预测就需要知道停顿时间的分布,而停顿时间则是由若干个步骤构成的,我们由中心极限定理可以知道,不管单个事件服从什么分布,只要其中大量的事件是独立的,这个总的分布就趋近于正态分布。 有了正态分布,我们就可以做预测,下一次随机变量的预测时间。一般的正态分布不太方便做计算和应用,因此我们需要做标准化转换。正态分布标准化转换的原因参看教科书。

Z变换:从一般正态分布到标准正态分布

对任意一个服从正态分布 X ~ N(μ, σ²)随机变量X ,经过如下变换,都可以将其转换为标准正态分布 N(0, 1)
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> z = X − μ σ z = \frac{X - \mu}{\sigma} </math>z=σX−μ

使用样本数据进行变换

在实际应用中,总体的均值 μ 和标准差 σ 往往是未知的。此时,可以利用从总体中抽取的样本均数 样本标准差 S 来进行计算:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> z = X − X ˉ S z = \frac{X - \bar{X}}{S} </math>z=SX−Xˉ
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> x = X ˉ + z ⋅ S x= Xˉ +z⋅S </math>x=Xˉ+z⋅S

有了上面的公式我们接着转换,我们引入置信度的概念,所谓置信度就是我们希望我们的预测有多大的把握是正确的,我们根据置信度可以查到对应的z因子。

G1也有一个置信度参数的,也就是G1ConfidencePercent。现在我们有了这个就可以做预测了,我们将G1的每一项开销都用这个方式来做预测,就构成了预测停顿时间模型。我们在src/hotspot/share/gc/g1/g1Predictions.hpp里面可以看到预测的逻辑也就是这样:

scss 复制代码
 double predict(TruncatedSeq const* seq) const {
    return seq->davg() + _stddev_scale * stddev_estimate(seq);
  }

参考资料

1\] JDK-8336912 [bugs.openjdk.org/browse/JDK-...](https://link.juejin.cn?target=https%3A%2F%2Fbugs.openjdk.org%2Fbrowse%2FJDK-8336912 "https://bugs.openjdk.org/browse/JDK-8336912") \[2\] 指数平滑和时间序列分解 [www.math.pku.edu.cn/teachers/li...](https://link.juejin.cn?target=https%3A%2F%2Fwww.math.pku.edu.cn%2Fteachers%2Flidf%2Fcourse%2Ffts%2Fftsnotes%2Fhtml%2F_ftsnotes%2Ffts-expsm.html "https://www.math.pku.edu.cn/teachers/lidf/course/fts/ftsnotes/html/_ftsnotes/fts-expsm.html") \[3\] [sdww2348115.github.io/jvm/g1/Paus...](https://link.juejin.cn?target=https%3A%2F%2Fsdww2348115.github.io%2Fjvm%2Fg1%2FPausePredictionModel "https://sdww2348115.github.io/jvm/g1/PausePredictionModel")

相关推荐
唐古乌梁海1 小时前
【Java】JVM 内存区域划分
java·开发语言·jvm
众俗2 小时前
JVM整理
jvm
echoyu.2 小时前
java源代码、字节码、jvm、jit、aot的关系
java·开发语言·jvm·八股
代码栈上的思考16 小时前
JVM中内存管理的策略
java·jvm
thginWalker19 小时前
深入浅出 Java 虚拟机之进阶部分
jvm
沐浴露z20 小时前
【JVM】详解 线程与协程
java·jvm
thginWalker1 天前
深入浅出 Java 虚拟机之实战部分
jvm
程序员卷卷狗2 天前
JVM 调优实战:从线上问题复盘到精细化内存治理
java·开发语言·jvm
Sincerelyplz3 天前
【JDK新特性】分代ZGC到底做了哪些优化?
java·jvm·后端
初学小白...4 天前
线程同步机制及三大不安全案例
java·开发语言·jvm