我们继承了一个在生产中运行并且最近每10小时开始失败的系统。基本上,如果一分钟没有响应,我们的内部软件会标记已失败的系统。我们发现我们的Full GC循环持续1.5分钟的问题,我们使用30 GB堆。现在问题是我们不能在短时间内优化很多,我们不能快速划分我们的服务,但我们需要尽快摆脱1.5分钟的暂停,因为我们的系统由于生产中的暂停而失败。对我们来说,可接受的延迟是20毫秒但不是更多。调整系统的最快方法是什么?减少堆以频繁触发GC?使用System.gc()提示?还有其他方法吗?我们使用Java 8默认设置,我们有越来越多的用户 - 即创建了越来越多的对象。
一些GC统计
对于您的问题,没有一个万能的灵丹妙药解决方案:您需要很好地处理应用程序的分配和活动模式,并且您需要知道它与特定垃圾收集算法的交互方式你正在运行(Java版本的功能和传递给java
的命令行标志)。
从广义上讲,Full GC(成功回收大量空间)意味着许多对象在次要集合中存活(但不会被泄露)。首先看一下你的伊甸园和幸存者空间的大小:如果伊甸园太小,那么次要的收藏品会非常频繁地运行,也许你没有给一个物体在达到它的终点阈值之前就有机会死亡。如果幸存者太小,物体将过早地被提升为老一代。
GC调整是一门艺术:您运行应用程序,研究结果,调整一些参数,然后再次运行它。因此,您将需要一个基准版本的应用程序,一个尽可能接近生产应用程序,但希望不需要10个小时就可以生成完整的GC。
正如您所说,您使用默认设置运行Java 8,我相信这意味着您的旧集合正在使用串行收集器运行。通过切换到旧代的并行收集器(-XX:+ UseParallelOldGC),您可能会看到一些非常快速的改进。虽然这可能会将1.5分钟的暂停时间减少到几秒钟(取决于盒子上的核心数量以及为GC指定的线程数量),但这不会将最大暂停时间减少到20毫秒。
你有很多保留的数据。有几个选项值得考虑。
long
的时间戳而不是Date
或LocalDateTime
。 (long
大小约为1/8)我建议分析数据的结构,看看是否有任何简单的方法可以提高数据的效率。
当发生这种情况时,这是由于静态变量占用内存导致的内存泄漏。我会仔细检查所有最近的代码更改,并寻找任何可能的内存泄漏。