对于不应暂停超过200毫秒的软实时系统的环境,我们正在寻找一种方法,在即将完成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时)。
我的问题:假设这一切都反映了长时间的峰值工作量(生产中任何给定时间点的工作量只会更低),这听起来像是一种有效的方法吗?您认为我们应该能够依靠GC日志中的最大空闲块大小统计信息来确定可靠性的程度吗?
我们绝对愿意接受建议,但要求他们仅限于HotSpot上的解决方案(No Azul对我们来说,至少目前为止)。此外,G1本身并不是解决方案,除非我们能够提出类似的指标,以便在Full GCs之前给我们提前警告,或者任何明显超过我们SLA的GC(这些可能会偶尔发生)。
答案 0 :(得分:2)
我在这里发布了来自Oracle的Jon Masamitsu的一个非常有启发性和令人鼓舞的答案的相关摘录,我从HotSpot GC邮件列表(hotspot-gc-use@openjdk.java.net)获得 - 他在HotSpot上工作,所以这确实是个好消息。
无论如何,这个问题现在仍然存在(我不能赞美自己引用电子邮件:-)),所以请添加你的建议!
格式化:原始帖子中的引号比Jon的响应更加缩进。
我们的理解是,只要最大的空闲块大小是 比年轻一代更大(假设没有羞怯的对象 分配),每个对象促销都应该成功。
在很大程度上这是正确的。有些情况下 从年轻一代升级到CMS一代的对象需要 CMS一代的空间比年轻一代更多。我不 认为这在很大程度上发生了。
以上是非常令人鼓舞的,因为我们绝对可以投入一些备用内存来防范他描述的罕见情况,听起来我们会做得很好。
< - 剪断 - >
我的问题:假设这一切都反映了一个长时间的高峰 工作量(生产中任何给定时间点的工作量) 低一点),这听起来像一个有效的方法吗?到什么程度 可靠性你认为我们应该能够指望最大值 GC日志中的免费块大小统计信息?
GC打印时的最大空闲块大小是准确的,但它 当你阅读并做出决定时,它可能会陈旧。
对于我们的工作负载,此指标位于非常缓慢的向下螺旋上,因此稍微陈旧不会对我们造成伤害。
< - 剪断 - >
我们绝对愿意接受建议,但要求他们提出建议 仅限HotSpot提供的解决方案(至少对我们来说是No Azul) 目前)。此外,G1本身并不是解决方案,除非我们能够提出 一个类似的指标,可以在Full GCs之前提前发出警告,或者 任何显着超过我们SLA的GC(偶尔也会如此) 发生)。
我认为使用最大免费块大小作为您的指标是一件好事 选择。它非常保守(听起来像你想要的)和 不受物体大小奇怪混合的影响。
对于G1我认为你可以使用完全免费区域的数量。 我不知道它是否在当前的任何日志中打印,但它是 可能是我们维持(或可能很容易)的指标。如果数量完全免费 随着时间的推移,地区会逐渐减少,这可能表明完整的GC即将到来。
乔恩
谢谢Jon!
答案 1 :(得分:0)
分而治之!
您的系统使用大量内存,需要高响应。因此,重新设计系统的架构,以实现展位。
确定关键的实时任务及其业务规则,以便为其创建Java进程。并使用任何非传统的编程实践,其想法是不依赖于GC来保持内存清洁。想一想,要有创意。
现在创建其他图层和流程,处理其余部分,并构建管道代码以连接所有内容。
即使你可以安排实时过程的生命,或检查他们的响应时间,杀死它并创建一个新的。但我可以期待你不需要杀死它,以保持高响应。
祝你好运!