我们有一个部署在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]
问题:
答案 0 :(得分:6)
当垃圾收集器决定收集每个垃圾收集器不同时。我的(并行GC)垃圾收集器运行时,我找不到任何硬性约定。许多垃圾收集器还会调整几个不同的变量,这些变量会影响它何时运行。
正如您已经注意到的那样,您的应用程序可能具有较高的堆使用率并仍然可以正常运行。您在应用程序中寻找的是垃圾收集器仍然有效。这意味着它可以在一次运行中清理大量垃圾。
大多数垃圾收集者都有两种或两种以上的策略,一种用于“年轻人”和“年轻人”。对象和一个用于“旧”的对象对象。当一个年轻的物体没有被收集在最新的(几个)收集中时,它就变成了一个旧物体。这背后的想法是,如果一个对象没有被收集,它可能也不会在下次收集。 (大多数物体要么活得很短,要么很长)。垃圾收集器对年轻物体进行了非常有效但不完美的清洁。当它没有释放足够的数据时,就会对所有(年轻的旧)对象进行更昂贵的垃圾收集。
这通常会产生锯齿(取自site): 在这里,您可以看到堆大小的许多小滴和缓慢增长的堆。每隔一段时间就会完成一个大型集合,并且有很大的下降。实际使用过的' memory是大量收集后剩余的内存量。
在确定应用程序的运行状况时,可以查看以下几个方面:
在大多数情况下,您需要在负载下监控应用程序的行为,以查看适合您的值。
并行垃圾收集器使用similar condition来确定是否所有内容仍然正常:
如果超过98%的总时间花在垃圾收集上,并且回收的堆少于2%,则抛出OutOfMemoryError。
使用VisualVM和Jconsole可以很好地看到所有这些统计信息。我不确定您可以在监控工具中使用哪个触发器