过度积极的垃圾收集主宰CPU

时间:2018-05-22 14:26:48

标签: java server configuration garbage-collection cpu-usage

我已经回顾了与我相似的其他问题,但它们似乎都没有像我所经历的那样覆盖一种情况。我的应用程序正常启动,以常规和预期的方式收集垃圾。

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 

1 个答案:

答案 0 :(得分:3)

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

基本上,如果你有一个堆,其中可达对象占用的空间不断向上趋势,并且运行垃圾收集器花费的时间越来越大。最终,堆将完全填满,或者GC Overhead Limit将被破坏。在任何一种情况下都会抛出OOME。

基本上有三种方法:

  1. 定期重启应用程序。
  2. 增加堆大小。
  3. 弄清楚您的应用程序使用越来越多的堆空间的原因。通常存在某种存储泄漏。
  4. 只有第3种方法才能真正解决问题。其他方法是"创可贴"的解决方案。

      

    当CPU处于使用状态时,我的应用程序无法正常工作。服务器有两个CPU,但JVM似乎只使用其中一个,而pidstat报告的平均使用率仅略高于100%。

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

    基本上,当堆太小而无法满足应用程序的需求时,GC不能很好地工作。