如何在Java中处理长满垃圾收集周期

问题描述 投票:2回答:3

我们继承了一个在生产中运行并且最近每10小时开始失败的系统。基本上,如果一分钟没有响应,我们的内部软件会标记已失败的系统。我们发现我们的Full GC循环持续1.5分钟的问题,我们使用30 GB堆。现在问题是我们不能在短时间内优化很多,我们不能快速划分我们的服务,但我们需要尽快摆脱1.5分钟的暂停,因为我们的系统由于生产中的暂停而失败。对我们来说,可接受的延迟是20毫秒但不是更多。调整系统的最快方法是什么?减少堆以频繁触发GC?使用System.gc()提示?还有其他方法吗?我们使用Java 8默认设置,我们有越来越多的用户 - 即创建了越来越多的对象。

一些GC统计

enter image description here

java garbage-collection jvm
3个回答
2
投票

对于您的问题,没有一个万能的灵丹妙药解决方案:您需要很好地处理应用程序的分配和活动模式,并且您需要知道它与特定垃圾收集算法的交互方式你正在运行(Java版本的功能和传递给java的命令行标志)。

从广义上讲,Full GC(成功回收大量空间)意味着许多对象在次要集合中存活(但不会被泄露)。首先看一下你的伊甸园和幸存者空间的大小:如果伊甸园太小,那么次要的收藏品会非常频繁地运行,也许你没有给一个物体在达到它的终点阈值之前就有机会死亡。如果幸存者太小,物体将过早地被提升为老一代。

GC调整是一门艺术:您运行应用程序,研究结果,调整一些参数,然后再次运行它。因此,您将需要一个基准版本的应用程序,一个尽可能接近生产应用程序,但希望不需要10个小时就可以生成完整的GC。

正如您所说,您使用默认设置运行Java 8,我相信这意味着您的旧集合正在使用串行收集器运行。通过切换到旧代的并行收集器(-XX:+ UseParallelOldGC),您可能会看到一些非常快速的改进。虽然这可能会将1.5分钟的暂停时间减少到几秒钟(取决于盒子上的核心数量以及为GC指定的线程数量),但这不会将最大暂停时间减少到20毫秒。


2
投票

你有很多保留的数据。有几个选项值得考虑。

  • 将堆增加到32 GB,如果你有空闲内存,这几乎没什么影响。再看一下你的总数,看起来你使用的是32 GB而不是30 GB,所以这可能没什么用。
  • 如果你没有足够的可用内存,可能会交换一小部分堆,因为这会大大增加GC的完整时间。
  • 可能有一些简单的方法可以使数据结构更紧凑。例如使用紧凑的字符串,使用原语代替包装,例如long的时间戳而不是DateLocalDateTime。 (long大小约为1/8)
  • 如果这些都没有帮助,请尝试从堆中移除一些数据。例如Chronicle Map是一个ConcurrentMap,它使用off heap memory可以大大减少GC时间。即堆存储的数据没有GC开销。高度添加的难易程度取决于数据的结构。

我建议分析数据的结构,看看是否有任何简单的方法可以提高数据的效率。


0
投票

当发生这种情况时,这是由于静态变量占用内存导致的内存泄漏。我会仔细检查所有最近的代码更改,并寻找任何可能的内存泄漏。

© www.soinside.com 2019 - 2024. All rights reserved.