JVM 堆使用百分比 - 何时生成警报

Posted

技术标签:

【中文标题】JVM 堆使用百分比 - 何时生成警报【英文标题】:JVM heap used percentage - when to generate alert 【发布时间】:2016-11-04 10:14:23 【问题描述】:

我们有一个应用程序部署在 Tomcat 8 应用程序服务器上,当前监控服务器 (Zabbix) 配置为在堆内存使用率为 90% 时生成警报。

生成的某些警报提示我们进行堆转储分析。堆转储中没有任何结果,没有内存泄漏。有很多不可达的对象因为没有 GC 而没有被清理。

JVM 配置:

-Xms8192m -Xmx8192m -XX:PermSize=128M -XX:MaxPermSize=256m 
-XX:+UseParallelGC -XX:NewRatio=3 -XX:+PrintGCDetails 
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/apache-tomcat-8.0.33 
-XX:ParallelGCThreads=2 
-Xloggc:/app/apache-tomcat-8.0.33/logs/gc.log 
-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps 
-XX:+PrintGCTimeStamps -XX:GCLogFileSize=50m -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=30

我们尝试使用jcmd 命令手动运行垃圾收集,它清除了内存。运行jcmd后的GC日志:

2016-11-04T03:06:31.751-0400: 1974627.198: [Full GC (System.gc()) [PSYoungGen: 18528K->0K(2049024K)] [ParOldGen: 5750601K->25745K(6291456K)] 5769129K->25745K(8340480K), [Metaspace: 21786K->21592K(1069056K)], 0.1337369 secs] [Times: user=0.19 sys=0.00, real=0.14 secs]

问题:

    上面是否有任何配置导致 GC 没有自动运行。 此行为的原因是什么?我知道Java会在需要时进行GC。但是,如果即使堆利用率为 90% 时它也没有运行 GC,那么警报阈值应该是多少(如果根据堆利用率发出任何警报是否有意义)。

【问题讨论】:

只是想知道:如果有一些“cron 作业”线程每天运行一次 System.gc() 会不会有意义?或者它会检查利用率并在您 > 80% 时运行 system.gc() ? @GhostCat:可以这样做,但不推荐。 GC 永远不能被强制,只能被请求。此外,问题陈述不是关于当 jvm 没有自动运行时如何运行 gc。我想知道它为什么没有运行,它等待的阈值是多少。 我把它作为评论是有原因的。这更像是一个实验的建议。是的,有时一个人应该努力去理解一切。但有时这样做代价高昂,可以使用廉价的解决方法来代替。这就是我想说的...... 一般来说,如果VM在任何堆空间中发生分配失败或达到占用阈值(在老年代空间中),就会触发GC。对于 CMS,该阈值是终身堆占用的initally > 90%。但这实际上取决于您使用的垃圾收集器、VM 版本和 VM 供应商。 @GhostCat:如果我试图解决问题,我会考虑解决方案。 90% 的堆利用率现在并没有受到影响。 【参考方案1】:

垃圾收集器决定收集的时间因垃圾收集器而异。当您的(并行 GC)垃圾收集器运行时,我无法找到任何硬性承诺。许多垃圾收集器还会调整几个不同的变量,这些变量会影响它的运行时间。

正如您自己所指出的,您的应用程序可能具有很高的堆使用率,但仍然可以正常运行。您在应用程序中寻找的是垃圾收集器仍然有效。这意味着它可以在一次运行中安静地清理大量垃圾。

垃圾回收的一些方面

大多数垃圾收集器有两种或多种策略,一种用于“年轻”对象,另一种用于“旧”对象。当一个年轻的对象在最近(几次)收集中没有被收集到时,它就变成了一个老对象。这背后的想法是,如果一个对象还没有被收集,那么它下次可能也不会被收集。 (大多数对象的寿命要么很短,要么很长)。垃圾收集器对年轻对象进行了非常有效但并不完美的清理。如果这不能释放足够的数据,则会对所有(年轻和年老)对象进行更昂贵的垃圾收集。

这通常会生成锯齿(取自site): 在这里,您会看到堆大小的许多小下降和缓慢增长的堆。时不时地完成一个大集合,并且有一个大的下降。实际“使用”的内存是大量收集后剩余的内存量。

要衡量的方面

这导致您在确定应用程序的运行状况时可以查看以下方面:

    您的应用程序垃圾收集所花费的时间(总时间和占 CPU 时间的百分比)。 垃圾回收后的可用内存量。 大型垃圾收集次数的快速增加。

在大多数情况下,您需要监控应用程序在负载下的行为,以了解对您来说什么是好的值。

并行垃圾收集器使用similar condition 来确定是否一切正常:

如果超过 98% 的总时间花在垃圾回收上,而回收的堆少于 2%,则抛出 OutOfMemoryError。

您可以使用 VisualVM 和 Jconsole 很好地查看所有这些统计信息。我不确定您可以将哪些用作监控工具中的触发器

【讨论】:

感谢您的详细回答:)

以上是关于JVM 堆使用百分比 - 何时生成警报的主要内容,如果未能解决你的问题,请参考以下文章

何时使用 k 折交叉验证以及何时使用拆分百分比?

Azure Application Insights 基于百分比的警报

当两个自定义指标之间的百分比差异超过指定百分比阈值时创建 Datadog 警报

如何根据失败百分比在日志字段中创建警报?

如何触发电池百分比更改的事件?

JVM自带监控工具