java - 过度激进的垃圾收集主导 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
解决方案
您正在描述垃圾收集“死亡螺旋”的症状。
基本上,如果您有一个堆,其中可访问对象占用的空间不断向上趋势,并且越来越多的时间用于运行垃圾收集器。最终,要么堆完全填满,要么超过 GC 开销限制。在任何一种情况下,都会抛出 OOME。
基本上有三种方法:
- 定期重新启动应用程序。
- 增加堆大小。
- 弄清楚为什么您的应用程序使用越来越多的堆空间。通常存在某种存储泄漏。
只有第三种方法才能真正解决问题其他方法都是“创可贴”的解决方案。
当 CPU 如此投入时,我的应用程序无法正常工作。服务器有两个 CPU,但 JVM 似乎只使用其中一个,pidstat 报告的平均使用率刚刚超过 100%。
如果 GC 承受的压力太大(例如由于“几乎满”的堆),那么您可能会发现它必须退回到非人体工程学的操作模式。例如,它可能决定在 JVM 启动时只创建一个后台 GC 线程,这通常很好,但在极端 GC 负载下,该线程会达到 100%,然后您的应用程序线程就会被阻塞。
基本上,当堆太小而无法满足应用程序的需求时,GC 无法正常工作。
推荐阅读
- windows - Rust Bindgen:在 Windows 上设置包含路径
- node.js - 无法理解 node.js lambda 函数在 mysql 查询后如何返回值
- android - 即使应用程序被用户关闭(例如instagram、whatsapp、facebook),如何创建一个永不停止运行的服务?
- python - 如何使用 LLDB python API `debugger.CreateTarget` 指定 dsym 文件
- javascript - 如何将函数变为异步
- gulp - 我正在尝试在使用 Gulp 4 时修复参考错误,它不会看到我的 sass 也不会显示浏览器中的更改
- python - 当数据集的尺寸为 [64 x 25088] 时,我应该为 `nn.Linear(1024, 256)` 设置什么值?
- javascript - 如何打印一个javascript字符串?
- mysql - 如何从多个表的坐标查询计算距离?
- html - 需要帮助使 2 个 iframe 具有响应性