【问题标题】:JVM OutOfMemory error "death spiral" (not memory leak)JVM OutOfMemory 错误“死亡螺旋”(不是内存泄漏)
【发布时间】:2010-02-19 16:34:11
【问题描述】:

我们最近将一些应用程序从在 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 已经奏效
  • 有时我们的应用程序会因 HotSpot SIGSEGV 错误而崩溃
  • 这会影响用 Java 和 Scala 编写的应用程序

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

这听起来很疯狂,但我只是看不出还有什么。你怎么能解释一个应用程序,它一分钟崩溃,最大堆为 1Gb,下一分钟工作正常(当应用程序执行完全相同的事情时,永远不会达到大约 256M)

所以我的问题是:

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

【问题讨论】:

  • 假设您可以重现问题:(1)创建导致失败的最小测试用例; (2)在另一个JVM下运行测试用例(openjdk.java.net); (3) 将测试用例发送给 Sun/Oracle。 JVM 不应违反段。
  • 是的 - 我可以想象它需要很长时间才能复制。我的意思是他们必须对这些东西进行测试,对吧?
  • 我有一个类似的问题:它也只发生在向应用程序提供大量数据时,但它总是触发一个 SIGSEGV,我不知道该怎么处理它,所以我提出了一个新问题:stackoverflow.com/questions/2299250/… 我的解决方法是同时使用 1.5 JVM。

标签: java scala jvm solaris out-of-memory


【解决方案1】:

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

您是否尝试过更改正在使用的垃圾收集器?有很多 GC 选项,找出哪些是最优的似乎有点玄学,但我想知道一个基本的改变是否适合你。

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

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

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

【讨论】:

  • 好吧,服务器是这种机器的默认设置。问题是这只发生在我们的生产服务器上,所以我不能只在我的电脑上修补(一切正常)。此外,之前对 GC 选项的混淆并没有让我认为任何东西都比默认设置更好。开始盲目地浏览选项将是一项艰巨的任务,但我尝试了这里推荐的高吞吐量但无济于事:java.sun.com/performance/reference/whitepapers/tuning.html
  • 如何监控您的内存使用情况并在 System.gc() 达到 3/4 满时运行两次。您还必须包括一种机制来确保这种情况不会经常发生,但如果您只是在数据突发时遇到问题,这可能是一个可行的解决方案。您可能还希望将您的最小内存设置为与您的最大值相同,以便它一次分配所有内存,而不是在突发期间 - 这使您的 3/4 完整测量更加可靠。
  • 我尝试将 Xms 设置为与 Xmx 相同,但没有任何区别。其中一个应用程序(基于批处理的)我已经添加了对 gc 的显式调用,我将在下周初看看结果如何
【解决方案2】:

我在 Solaris 机器上遇到过同样的问题,我通过 减小 JVM 的最大大小解决了这个问题。 32 位 Solaris 实现显然需要一些开销空间,超出了在进行垃圾收集时为 JVM 分配的空间。因此,例如,使用 -Xmx3580M 我会得到您描述的错误,但使用 -Xmx3072M 就可以了。

【讨论】:

  • 但是这些应用程序真的不是很大——通常是 256Mb 并且它们所在的机器是野兽(24Gb 的 RAM)并且目前没有得到充分利用。我看不出为什么 solaris 找不到任何额外的内存来做家务!
  • 也许它与数据吞吐量和/或 GC 负载成正比,而你的比我的高很多?您将最大堆大小设置为多少?
  • 我最终绝望地把它提升到 1Gb,看着应用程序愉快地启动,从来没有超过 256Mb!但这不是确定性的(第一次没有工作)——失败了,失败了,失败了,失败了,成功了!
【解决方案3】:
  1. 是的,我之前观察到过这种行为,通常在调整 JVM 参数无数小时后它开始工作。
  2. 垃圾收集,尤其是在多线程情况下是不确定的。在非确定性代码中定义错误可能是一项挑战。但如果您使用的是 Solaris,则可以尝试 DTrace,并且有很多 JVM 选项可用于窥视 HotSpot。
  3. 继续使用 Scala IRC 并查看 Ismael Juma 是否在闲逛 (ijuma)。他以前帮助过我,但我认为真正深入的帮助需要付出代价。
  4. 我认为大多数从事此类工作的人都接受,他们要么需要成为 JVM 调优专家,要么拥有一名员工,要么聘请一名顾问。有些人专门研究 JVM 调优。

为了解决这些问题,我认为您需要能够在受控环境中复制它们,您可以在其中精确复制具有不同调整参数和/或代码更改的运行。如果你不能做到这一点,那么聘请专家可能对你没有任何好处,而解决问题的最便宜的方法可能是购买更多的 RAM。

【讨论】:

    【解决方案4】:

    你得到什么样的 OutOfMemoryError?堆空间是否已用尽或与任何其他内存池相关的问题(错误通常有一条消息提供有关其原因的更多详细信息)。

    如果堆耗尽并且可以重现问题(听起来好像可以),我首先会配置 VM 以在 OutOfMemoryErrors 上生成堆转储。然后,您可以分析堆并确保它没有被对象填充,这些对象仍然可以通过一些意外引用访问。

    您遇到 VM 错误当然不是不可能的,但如果您的应用程序依赖于 1.6.0_03 中的实现特定行为,则在 1.6 上运行时可能由于某种原因导致内存占用。 0_16。如果您为应用程序使用某种服务器容器,也可能会发现此类问题。一些开发人员显然无法阅读文档,但倾向于观察 API 行为并对某些东西应该如何工作做出自己的结论。当然,这并不总是正确的,我在 Tomcat 和 JBoss 上都遇到了类似的问题(这两种产品至少曾经只用于特定的虚拟机)。

    【讨论】:

    • jhat 似乎无法分析任何大小 >= 256Mb 的堆,不幸的是因为 内存不足!它是“堆耗尽”和“超出 GC 开销限制”错误的混合,并且它没有在容器中运行(除了 Spring)
    • 有人告诉我尝试 YourKit,但我不愿花时间在这种方法上。毕竟,如果应用程序在 1.6.0_03/linux 上运行但不在 1.6.0_18/solaris 上运行,那么问题肯定出在 VM 上 - 分析我的堆有什么帮助?
    • 我使用的是 Eclipse 内存分析器 (eclipse.org/mat),也许你想看看它?我已经在回答中解释了为什么您的问题不一定是由 VM 错误引起的,以及为什么我认为您应该仔细查看堆转储。
    • @Jarnbjo - 我不确定你是否解释过类似的情况:应用程序运行良好 3 年,然后在迁移到新 VM 时开始崩溃,这是内存泄漏?跨度>
    • 简短摘要:如果您的应用程序依赖于 VM 实现(而不是记录在案的)行为,那么您看到的问题可能不是 VM 错误,而是您的应用程序中的错误。
    【解决方案5】:

    还要确保它不是硬件故障(尝试在服务器上运行 MemTest86 或类似的东西。)

    【讨论】:

      【解决方案6】:

      您究竟遇到了哪种 SIGSEV 错误?

      如果您运行 32 位 VM,可能是我在此处描述的:http://janvanbesien.blogspot.com/2009/08/mysterious-jvm-crashes-explained.html

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-11-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-30
        相关资源
        最近更新 更多