过于激进的垃圾回收占用CPU过多

5

我已经查看了其他与我的题目类似的问题,但是它们似乎都没有涵盖我正在遇到的情况。我的应用程序正常启动,按照预期的方式进行垃圾回收。

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个回答

3
您正在描述垃圾收集“死亡螺旋”的症状。如果您的堆中可达对象所占空间不断增加,并且越来越多的时间用于运行垃圾回收器,则堆最终将完全填满,或者将超过GC Overhead Limit。在任何一种情况下,都会抛出OOME(OutOfMemoryError)异常。
基本上有三种方法:
1.定期重新启动应用程序。 2.增加堆大小。 3.找出为什么应用程序使用越来越多的堆空间。通常存在某种存储泄漏。
只有第三种方法才真正解决了问题。其他方法只是“绷带式”解决方案。
当CPU受到过度压力(例如由于“几乎满”的堆)时,您可能会发现它必须退回到非人体工程学模式。例如,它可能已经决定在JVM启动时仅创建一个后台GC线程,这通常很好,但在极端GC负载下,该线程达到100%,然后阻塞您的应用程序线程。
基本上,GC在堆对应用程序需求过小的情况下无法正常工作。

在我的情况下,它似乎不太像“螺旋”,更像是“尖峰”。垃圾回收似乎相当健康,直到突然开始每秒运行多次。这是一个典型的模式吗? - Jeremy
  1. 如果您的应用程序在某个阶段消耗了几乎所有可用堆空间(作为可达对象)...然后返回到“正常”状态,那么可能会发生这种情况。
  2. 不要排除这是“死亡螺旋”的开始的可能性。 问:这是典型的吗?答:定义“典型” :-)
- Stephen C
一旦进入“panic”模式,我的应用程序直到我重新启动它才能返回“正常”状态,因此无论是尖峰还是螺旋,它似乎都是死亡。是否有可能监视正在进行垃圾回收的对象,以诊断并纠正可能导致此问题的代码中的任何问题? - Jeremy
监控对象的创建和/或垃圾回收往往是困难的,可能会改变应用程序的行为,并且很可能无法找到问题。查找原因的标准方法是获取堆转储并使用内存分析工具对其进行分析,以查找哪些对象正在泄漏(或获取两个转储并比较它们)。从那里,您通常可以找出它们为什么泄漏...并修复它。 - Stephen C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接