2014-10-08 31 views
11

我们有一个应用程序,它生成新的JVM并代表我们的用户执行代码。有时那些内存不足,在这种情况下,行为方式非常不同。有时他们会抛出OutOfMemoryError,有时会冻结。我可以通过一个非常轻量级的后台线程检测后者,在内存不足时发送心跳信号。在这种情况下,我们杀死了JVM,但我们永远无法确定无法接收心跳的真正原因。 (这可能是网络问题或分段错误。)处理Java内存不足情况的最佳方法是什么?

什么是可靠地检测JVM内存不足情况的最佳方法?

  • 从理论上讲,-XX:OnOutOfMemoryError选项看起来很有希望,但它的使用效率,由于这个错误:https://bugs.openjdk.java.net/browse/JDK-8027434

  • 捕获OutOfMemoryError而实际上不是众所周知的原因一个很好的选择(例如你永远不知道它发生在哪里),尽管它在很多情况下都有效。

  • 剩下的情况是那些JVM冻结并且不会抛出OutOfMemoryError的情况。我仍然确定内存这个问题的原因。

是否有任何替代方案或解决方法?垃圾收集设置使JVM自行终止而不是冻结?

编辑:我完全控制分叉和分叉的JVM以及在那些内部执行的代码,两者都在Linux上运行,并且如果有帮助的话,可以使用特定于操作系统的实用程序。

+2

这听起来像你真正感兴趣的是检测何时在另一个进程*中发生了内存不足的情况;一个关键点甚至没有被你的问题的标题暗示。 – supercat 2014-10-08 17:39:23

+0

谢谢。我试图在帖子中说得更清楚,但迄今为止我还没有改变标题,因为我所能提出的所有替代标题都是误导性的。特别是我不介意我们是从JVM内部还是从调用的JVM中获取信息,将其视为具有特定行为的JVM,或者将其视为一个流程。 – 2014-10-08 18:02:13

+2

如果你没有提高你的头衔,许多可能会回答的人甚至不可能打开你的帖子。也许“如果Java VM进程内存不足会触发警报”会是一个更好的标题? – supercat 2014-10-08 18:08:13

回答

1

这个经历过了相当一段时间后,这是对我们工作的解决方案:

  1. 在催生JVM,立即赶了OutOfMemoryError和出口,标志着内存不足与退出代码以控制JVM 。
  2. 在衍生的JVM中,定期检查当前消耗的内存量Runtime。当使用的内存量接近关键时,创建一个标志文件,将内存不足情况发送给控制器JVM。如果我们从这种情况恢复并正常退出,请在退出之前删除该文件。
  3. 控制JVM加入分叉的JVM之后,它会检查步骤(1)中生成的退出代码和步骤(2)中生成的标志文件。除此之外,它还检查文件hs_err_pidXXX.log是否存在并包含“Out of Memory Error”行。 (这个文件是由java生成的,如果它崩溃的话)

只有在实现所有这些检查之后,我们才能够处理所有分叉JVM内存不足的情况。我们相信从那以后,我们并没有错过发生这种情况的情况。

java flag -XX:OnOutOfMemoryError由于fork问题而没有使用,因为堆转储比我们需要的更多,所以不使用-XX:+HeapDumpOnOutOfMemoryError

该解决方案当然不是最优雅的一段代码,但为我们做了这份工作。

0

如果您对应用程序和配置都有控制权,最好的解决方案是找到引发OutOfMemoryError的根本原因并解决此问题,而不是通过捕获错误或仅仅通过捕获错误来隐藏症状重新启动JVM。

从你所描述的看,无论是在JVM上运行的应用程序是在泄漏内存,还是在运行中使用资源不足(内存在你的情况下),或者偶尔处理需要异常大堆的事务。这些案例的解决方案可能会有所不同:

  1. 如果发生内存泄漏,请找到潜在的原因并让工程师修复它。此工具包括堆转储分析器,分析器或泄漏检测器
  2. 如果资源调配不足的资源需要监视应用程序内存消耗,例如通过垃圾收集日志,并根据您面对的内容调整不同内存池的大小。
  3. 如果在用户交易过程中发生浪涌分配,您需要追踪导致浪涌的代码并让工程师修复它 - 通过禁用某些用户输入或以较小批量加载和处理数据。线程转储或进程中的堆转储都可以引导您转向解决方案。
+0

从我认为这个问题没有单一的原因OutOfMemory,只是运行任意用户代码。我不认为他在问如何解决用户的代码 – 2014-10-09 09:00:18

+0

这是正确的。人们向我们提交工作流程(将其视为可视化编程)。我们在分叉的JVM中运行它们。如果这样的工作流程在16 GB数据文件上选择这样做时对16 GB数据文件执行矩阵操作,则无法工作。调用者必须修复它,但我们需要告诉他们内存是问题,而不是JVM错误或其他错误。 – 2014-10-09 22:00:30

+0

在这种情况下,Plumbr(https://plumbr.eu)可以做到这一点 - 例如在内存泄漏的情况下,您将得到确切的根本原因,您可以将其发送给基于该原因的工程人员,然后立即放大底层因为来自Plumbr的事件报告引用了问题源代码中的确切代码。 – Ivo 2014-10-10 17:15:45

1

唯一真正的选择是(不幸地)尽快终止虚拟机。

由于您可能不能更改所有代码来捕获错误并作出响应。如果你不相信OnOutOfMemoryError(我不知道为什么它不应该使用的是由Java使用8 vfork的,它适用于Windows),你至少可以触发堆转储和外部监控这些文件:

java .... -XX:+HeapDumpOnOutOfMemoryError "-XX:OnOutOfMemeoryError=kill %p" 
+0

-XX:+ HeapDumpOnOutOfMemoryError实际上是我们尚未尝试的选项。到目前为止,它似乎也没有得到可靠的创造。 WRT的-XX:OnOutOfMemoryError:它确实有效,但只有当操作系统有大约50%的内存仍然可用时,在这种情况下,我宁愿将它提供给JVM,而不仅仅用于此目的:-) – 2014-10-09 22:08:26

+0

@SimonFischer恕我直言JRE切换到运行时#exec()的vfork,我不知道这是否也包括OnOutOfMemory。但当然,它可能无法在空间有限的条件下执行命令是正确的。如果他们是选项,我不确定CrashReporter服务器和OS Creash报告。毕竟,无论如何你都需要检查消失的过程。 – eckes 2014-10-13 00:00:37

相关问题