对于不应暂停超过200毫秒的软实时系统,我们正在寻找一种在即将推出Full GC之前发出预警的方法。我们意识到我们可能无法避免这种情况,但是我们想在系统停止运行之前故障转移到另一个节点。
我们已经能够提出一种方案,该方案可以在即将发生的完整GC之前向我们提供提前警告,这可能会导致系统停止运行几秒钟(我们需要避免)。
我们能够提供的服务依赖于CMS免费列表统计信息:-XX:PrintFLSStatistics=1
。这会在每个GC周期(包括年轻的GC)之后将空闲列表统计信息打印到GC日志中,因此该信息在较短的时间间隔内可用,并且在内存分配率较高的时间间隔内会更加频繁地出现。就性能而言,它可能会花费一点钱,但是我们的工作假设是我们可以负担得起。
日志的输出如下所示:
Statistics for BinaryTreeDictionary:
------------------------------------
Total Free Space: 382153298
Max Chunk Size: 382064598
Number of Blocks: 28
Av. Block Size: 13648332
Tree Height: 8
特别是,最大空闲块大小为382064598个字。如果使用64位字,则总计应不到2915MB。这个数字的下降速度非常缓慢,大约每小时1MB。
我们的理解是,只要最大空闲块大小大于年轻代(假设没有笨拙的对象分配),则每次对象升级都应成功。
最近,我们进行了几天的压力测试,发现CMS能够将最大块大小保持在旧区域总空间的94%以上。最大可用块大小似乎正在以小于1MB/小时的速度减小,这应该很好-根据此信息,我们不会很快达到完整的GC,服务器可能会因维护而停机可能比完全GC发生的频率更高。
在以前的测试中,在系统内存效率较低的时候,我们已经能够将系统运行10个小时。在最初的一个小时内,最大可用块大小已减少到100MB,并保持了8个小时以上。在运行的最后40分钟内,当发生完全GC时,最大空闲块大小以稳定的速率减小至0,这非常令人鼓舞,因为对于该工作负载,我们似乎可以提前40分钟警告(当数据块大小开始逐渐趋向于0时)。
我的问题是:假设所有这些都反射(reflect)了长时间的高峰工作量(生产中任何给定时间点的工作量只会减少),这听起来像是一种有效的方法吗?您认为我们应该能够从GC日志中获得最大程度的可靠性吗?
我们绝对欢迎您提出建议,但要求它们仅限于HotSpot上可用的解决方案(至少对于我们而言,暂时没有Azul)。此外,G1本身并不是解决方案,除非我们可以提出一个类似的指标,该指标将在完整GC或任何显着超过我们的SLA的GC(有时会发生)之前给我们提前警告。
最佳答案
我在这里发布了来自Oracle的Jon Masamitsu的一个非常令人鼓舞和令人鼓舞的答案的相关摘录,我从HotSpot GC邮件列表(hotspot-gc-use@openjdk.java.net)中得到了-他致力于HotSpot,所以这是确实是个好消息。
无论如何,这个问题现在仍然悬而未决(我不能相信自己引用电子邮件:-)),所以请添加您的建议!
格式:原始帖子的引号比Jon的回复缩进更多。
在很大程度上,这是正确的。有情况下
从年轻一代提升为CMS一代的对象需要
CMS一代比年轻一代拥有更多的空间。我不
认为这在很大程度上发生了。
上面的内容非常令人鼓舞,因为我们可以肯定地分配一些备用内存来防止他描述的罕见情况,而且听起来我们会做得很好。
最大空闲块大小在GC打印时是准确的,但是它是
当您阅读并做出决定时可能会过时。
对于我们的工作负载,此指标处于非常缓慢的下降螺旋中,因此有些陈旧不会损害我们。
我认为使用最大空闲块大小作为度量标准是一个很好的选择
选择。这是非常保守的(听起来像您想要的),并且
不受对象大小的奇怪混合影响。
对于G1,我认为您可以使用完全自由区域的数量。
我不知道它是否当前打印在任何日志中,但是它是
可能是我们维护的指标(或很容易)。如果数量完全免费
区域随着时间的推移而减少,这可能表明即将出现完整的GC。
乔恩
谢谢乔恩!