如何预测JVM垃圾回收?

3

我正在处理一项关键的Java应用程序,需要避免“停止世界垃圾回收”效应。我正在寻找一种可以预测由于完整GC而导致的长时间暂停的解决方案。是否有可能实现?


如果有时可以接受GC,您可以尝试调用System.gc()。当此调用返回时,不太可能在不久的将来发生新的GC。 - Ole V.V.
这个问题与统计预测无关,因此“prediction”标签可能被错误地放置了。 - slonopotam
@Ole V.V. gc() 可能很容易不会发生或被禁用。 "不久的将来" 是一个模糊的术语,新 GC 的可能性完全取决于 OP 系统的具体情况、其运行时配置文件和其错误,而我们对此一无所知。因此,我们还不能负责任地断言 gc() 会产生什么影响。 - Lew Bloch
1
对于延迟敏感的应用程序,常见的方法不是尝试预测暂停,而是测量然后减少它们。 - the8472
@LewBloch 当然,GC可以被禁用,但是有人已经禁用了它。在您自己的服务器上很容易避免这种情况。您可以测试它,如果它有效,您可以依赖它。话虽如此,可能有更好的解决方案。 - maaartinus
系统可以自由地忽略gc调用,即使它们没有被明确禁用,而且它们会产生重大的GC而不仅仅是小的GC,所以你真的不能依赖它们。 - Lew Bloch
3个回答

5
您可以做的最好的事情就是减少分配,或者使用像Azul这样的暂停较少的GC。这将使GC更易于管理。
如果您在关键部分(使用度量标准例如JMC / JFR之类的分析工具)中足够减少分配,您可以整天运行而不进行完全收集,或者在极端情况下,整天运行而不进行小型收集。
您可以监视tenured空间的占用情况,并查看它是否正在填充(存在其他导致full GC的原因,但这是最常见的原因)。

1
“减少分配”可能会严重恶化GC性能,因为人们为了减少分配而做的大多数事情会导致对象存活,直到它们被提升为“终身”。这不是建议盲目遵循的。更好的建议是在算法允许的最窄范围内分配引用,以便年轻代GC成为规则,并尽早释放对象以避免内存泄漏(packratting)。此外,设计对象需要最小的初始化。遵循最佳的内在程序逻辑以获得最佳的GC配置文件。 - Lew Bloch
@LewBloch 分配对象涉及工作,应尽量避免。理想情况下,逃逸分析可以消除分配,因此我会避免优化代码,JIT可以为您优化,即仅在运行时删除实际分配,而不是您认为的分配发生的地方。但是,您确实希望避免对象死在老年空间中,尽管我很少见到这种情况,特别是如果您可以进行更少的次要收集。 - Peter Lawrey
分配对象几乎不需要时间,可能只需要十到十二条机器指令。内存系统保证JVM仅需存储一个指针并增加堆顶标记。需要时间的是初始化。我的建议考虑了这一点,并像您的建议一样,主张避免对象达到老年代。大多数对象应该让其早日离世。 - Lew Bloch
@LewBloch 分配所造成的内存压力会降低缓存效率并减慢每个内存访问速度,通过在关键部分减少分配,您可以将应用程序的性能提高2-5倍。 - Peter Lawrey
也许是这样,也许不是。这取决于程序的运行特性。只有在现实世界中进行实际测量才能确定。先验地进行这种“优化”不太可能产生有用的改进。但无论如何,您必须为应用程序分配必要的对象。保持生命周期短可以减少内存中同时存在的对象数量,这有助于缓存问题。将对象保留到终身代会引起问题,这会淹没微小优化的收益。 - Lew Bloch
1
@LewBloch 我同意,不集中精力地更改代码很可能会在性能方面带来正反两面的影响,但增加复杂性将使维护变得更加困难。只有通过度量驱动的代码优化才是有意义的,例如使用像jfr这样的分析工具。 - Peter Lawrey

2

这完全不可能。我认为避免“停止世界”垃圾回收的最佳方法是尽量减少对象的生命周期,进行小批量运行。

顺便说一下,您需要尝试不同的解决方案并对其进行分析。


1
这是一条关于编程的建议,它允许年轻一代的垃圾收集器占主导地位,在分配几乎是自由的情况下,而且完全免费回收,同时确保活动对象的副本尽可能小。 - Lew Bloch

0
为什么不按内存使用情况定期强制进行GC呢?

因为你不能? - Lew Bloch

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