我无法找到一种方法来监视 JVM GC 的内存耗尽问题。
使用串行 GC,我们只需查看完整的 GC 暂停时间,就可以很好地了解 JVM 是否遇到问题(例如,是否花费了超过几秒的时间)。
CMS 的行为似乎有所不同。
当从 lastGcInfo
MXBean(通过 JMX)查询 java.lang:type=GarbageCollector,name=ConcurrentMarkSweep
时,报告的持续时间是所有 GC 步骤的总和,通常为几秒长。这并不表明 GC 存在问题,相反,我发现太短的 GC 时间通常更多地表明存在问题(例如,如果 JVM 进入 CMS-concurrent-mark-start
-> concurrent mode failure
循环,就会发生这种情况)。
我也尝试过 jstat
,它给出了垃圾收集所花费的累积时间(不确定是用于旧的还是新的 GC)。可以将其绘制成图表,但用于监控目的并非易事。例如,我可以解析 jstat -gccause
输出并计算随时间变化的差异,并跟踪+监控(例如,过去 X 分钟内 GC 所花费的时间)。
我使用以下 JVM 参数进行 GC 日志记录:
-Xloggc:/xxx/gc.log
-XX:+PrintGCDetails
-verbose:gc
-XX:+PrintGCDateStamps
-XX:+PrintReferenceGC
-XX:+PrintPromotionFailure
如果没有其他可用的方法,解析 gc.log 也是一种选择,但最佳解决方案是使用 java 原生方法来获取相关信息。
信息必须是机器可读的(以发送到监控平台),因此不能选择可视化工具。我正在运行一个混合有 JDK 6/7/8 实例的生产环境,因此版本无关的解决方案更好。
是否有一种简单的方法来监控 CMS 垃圾回收?我应该关注哪些指标?
最佳答案
从根本上来说,人们希望从 CMS 并发收集器获得两件事
- 并发周期跟上提升率的吞吐量,即单位时间内存活到旧代的对象
- 老年代中有足够的空间用于在并发周期期间提升对象
因此,假设 IHOP 固定为 70%,那么当它在某个时刻达到 >90% 时,您可能会遇到问题。如果您进行一些不适合年轻一代或比年轻一代生命周期更长的大型分配(这完全是特定于应用程序的),则可能会更早。 此外,您通常希望它在并发周期之外花费比在并发周期内更多的时间,尽管这取决于您调整收集器的紧密程度,原则上您可以让并发周期几乎一直运行,但这样您的吞吐量裕度就很小并在并发收集上消耗大量 CPU 时间。
如果您确实想避免偶尔的 Full GC,那么由于碎片(CMS 是非压缩的),您将需要更多的安全余量。我认为这无法通过 MX beans 进行监控,您必须启用一些特定于 CMS 的 GC 日志记录才能获取碎片信息。
关于Java:如何跟踪/监视 CMS 垃圾收集器的 GC 时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43138847/