首页 > 解决方案 > 过度激进的垃圾收集主导 CPU

问题描述

我已经查看了与我的标题相似的其他问题,但它们似乎都没有涵盖与我正在经历的情况非常相似的情况。我的应用程序正常启动,垃圾收集以例行和预期的方式。

2018-05-21T20:08:41.136-0400: 19979.368: [GC (Allocation Failure) [PSYoungGen: 71364K->10997K(73728K)] 303964K->243661K(466944K), 0.0165899 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
2018-05-21T20:09:01.212-0400: 19999.444: [GC (Allocation Failure) [PSYoungGen: 71413K->11065K(73728K)] 304077K->243865K(466944K), 0.0121248 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 
2018-05-21T20:09:30.450-0400: 20028.682: [GC (Allocation Failure) [PSYoungGen: 71481K->12550K(73728K)] 304281K->245422K(466944K), 0.0133476 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 
2018-05-21T20:09:50.492-0400: 20048.723: [GC (Allocation Failure) [PSYoungGen: 72966K->10454K(73728K)] 305838K->243374K(466944K), 0.0141533 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 

在看似任意的时间之后,垃圾收集变得非常激进,每秒运行数次并消耗 CPU 的整个运行时间。它会一直保持这种状态,直到应用程序重新启动。

2018-05-21T20:10:12.104-0400: 20070.335: [GC (Allocation Failure) [PSYoungGen: 70870K->10356K(73728K)] 303790K->243340K(466944K), 0.0193899 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 
2018-05-21T20:10:12.222-0400: 20070.453: [GC (Allocation Failure) [PSYoungGen: 70772K->2080K(72704K)] 303756K->235288K(465920K), 0.0090667 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
2018-05-21T20:10:12.413-0400: 20070.645: [GC (Allocation Failure) [PSYoungGen: 61472K->1936K(73728K)] 294680K->235256K(466944K), 0.0081242 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
2018-05-21T20:10:12.519-0400: 20070.751: [GC (Allocation Failure) [PSYoungGen: 61328K->1585K(81408K)] 294648K->235248K(474624K), 0.0053709 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
2018-05-21T20:10:12.582-0400: 20070.813: [GC (Allocation Failure) [PSYoungGen: 67633K->1313K(82432K)] 301296K->235240K(475648K), 0.0080559 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
2018-05-21T20:10:12.647-0400: 20070.878: [GC (Allocation Failure) [PSYoungGen: 67361K->1121K(92160K)] 301288K->235264K(485376K), 0.0052482 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
2018-05-21T20:10:12.718-0400: 20070.950: [GC (Allocation Failure) [PSYoungGen: 76897K->801K(92672K)] 311040K->235256K(485888K), 0.0071820 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
2018-05-21T20:10:12.792-0400: 20071.024: [GC (Allocation Failure) [PSYoungGen: 76577K->641K(105472K)] 311032K->235232K(498688K), 0.0070387 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
2018-05-21T20:10:12.878-0400: 20071.109: [GC (Allocation Failure) [PSYoungGen: 89217K->32K(105472K)] 323808K->235249K(498688K), 0.0084592 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
2018-05-21T20:10:12.962-0400: 20071.194: [GC (Allocation Failure) [PSYoungGen: 88608K->64K(119296K)] 323825K->235289K(512512K), 0.0066050 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

当 CPU 如此投入时,我的应用程序无法正常工作。服务器有两个 CPU,但 JVM 似乎只使用其中一个,pidstat 报告的平均使用率刚刚超过 100%。

这种行为最让我困惑的是,年轻一代被驱动到分配给它的一小部分空间并保留在那里,在垃圾收集后永远不会超过 1 Mb。

我怎样才能防止这种情况发生,或者我能做些什么来诊断为什么会发生这种情况?我不是调整垃圾收集方面的专家,所以我可以使用一些资深的指导。

我当前的 JVM 配置是:

-XX:InitialHeapSize=268435456 
-XX:MaxHeapSize=2147483648 
-XX:+PrintGC 
-XX:+PrintGCDateStamps 
-XX:+PrintGCDetails 
-XX:+PrintGCTimeStamps 
-XX:+UseCompressedClassPointers 
-XX:+UseCompressedOops 
-XX:+UseParallelGC 

标签: javaserverconfigurationgarbage-collectioncpu-usage

解决方案


您正在描述垃圾收集“死亡螺旋”的症状。

基本上,如果您有一个堆,其中可访问对象占用的空间不断向上趋势,并且越来越多的时间用于运行垃圾收集器。最终,要么堆完全填满,要么超过 GC 开销限制。在任何一种情况下,都会抛出 OOME。

基本上有三种方法:

  1. 定期重新启动应用程序。
  2. 增加堆大小。
  3. 弄清楚为什么您的应用程序使用越来越多的堆空间。通常存在某种存储泄漏。

只有第三种方法才能真正解决问题其他方法都是“创可贴”的解决方案。


当 CPU 如此投入时,我的应用程序无法正常工作。服务器有两个 CPU,但 JVM 似乎只使用其中一个,pidstat 报告的平均使用率刚刚超过 100%。

如果 GC 承受的压力太大(例如由于“几乎满”的堆),那么您可能会发现它必须退回到非人体工程学的操作模式。例如,它可能决定在 JVM 启动时只创建一个后台 GC 线程,这通常很好,但在极端 GC 负载下,该线程会达到 100%,然后您的应用程序线程就会被阻塞。

基本上,当堆太小而无法满足应用程序的需求时,GC 无法正常工作。


推荐阅读