JVM OutOfMemory 错误“死亡螺旋”(不是内存泄漏)

2022-09-02 14:02:01

我们最近将许多应用程序从在RedHat linux JDK1.6.0_03下运行迁移到Solaris 10u8 JDK1.6.0_16(更高规格的机器),我们注意到一个似乎相当紧迫的问题:在某些负载下,我们的JVM会让自己陷入“死亡螺旋”并最终耗尽内存。注意事项:

  • 这不是内存泄漏的情况。这些应用程序运行良好(在一种情况下运行了3年以上),并且在任何情况下都不确定内存不足的错误。有时应用程序工作,有时它们不起作用
  • 这不是我们移动到64位VM - 我们仍然运行32位
  • 在一种情况下,在1.6.0_18上使用最新的G1垃圾回收器似乎已经解决了这个问题。在另一个中,移回1.6.0_03已经奏效了
  • 有时我们的应用程序会因热点错误而崩溃SIGSEGV
  • 这影响了用Java和Scala编写的应用程序。

最重要的一点是:这种行为表现在那些突然获得大量数据(通常通过TCP)的应用程序中。就好像VM决定继续添加更多数据(可能将其推进到TG)而不是在“newspace”上运行GC,直到它意识到它必须执行完整的GC,然后,尽管VM中几乎所有内容都是垃圾,但它以某种方式决定不收集它!

这听起来很疯狂,但我只是不明白它是什么。否则你怎么能解释一个应用程序,一分钟倒下,最大堆为1Gb,下一个工作得很好(当应用程序做完全相同的事情时,永远不会大约256M)

所以我的问题是:

  1. 有没有人观察到这种行为?
  2. 有没有人对我如何调试JVM本身(而不是我的应用程序)有任何建议?如何证明这是 VM 问题?
  3. 是否有任何 VM 专家论坛,我可以在其中询问 VM 的作者(假设他们不在 SO 上)?(我们没有支持合同)
  4. 如果这是最新版本的 VM 中的一个错误,为什么没有其他人注意到它?

答案 1

有趣的问题。听起来像是其中一个垃圾回收器在您的特定情况下效果不佳。

您是否尝试过更改正在使用的垃圾回收器?有很多GC选项,找出哪些是最佳的似乎有点黑色艺术,但我想知道基本的改变是否适合你。

我知道有一个“服务器”GC往往比默认的GC工作得更好。你在用吗?

线程GC(我认为这是默认设置)可能是您特定情况下最糟糕的,我注意到当机器繁忙时,它往往不那么激进。

我注意到的一件事是,通常需要两个GC才能说服Java真正清除垃圾。我认为第一个倾向于取消链接一堆对象,第二个实际上删除了它们。您可能想做的是偶尔强制两个垃圾回收。这将导致GC暂停,但我从未见过清理整个堆花费两个以上的情况。


答案 2

我在 Solaris 机器上也遇到了同样的问题,我通过减小 JVM 的最大大小解决了这个问题。32 位 Solaris 实现显然需要一些开销空间,而不是在执行垃圾回收时为 JVM 分配的空间。因此,例如,我会得到您描述的错误,但这样做会很好。-Xmx3580M-Xmx3072M


推荐