5

我有一个在 java (1.6) 中运行的关键进程,带有一个已注册的关闭挂钩。在某些情况下,我遇到了 OOM 问题(下面有关于该问题的更多详细信息),进程突然停止,我没有得到任何日志,我的 catch(Throable x) 没有捕获异常。

但是关闭挂钩有效。因此,如果有办法知道该进程将由于一些讨厌的 OOM 而关闭,我可以在退出之前记录必要的信息。

有没有办法做到这一点?

关于 OOM:不确定是什么异常,因为正如我所说,它没有被捕获。我知道这是一个 OOM,因为我开始这个过程

-XX:+HeapDumpOnOutOfMemoryError

我得到一个堆转储文件。在其他情况下,会捕获一个异常,这是一个 ava.lang.OutOfMemoryError: GC 开销限制超出。但不确定是否总是这样。

编辑:

如果不清楚:我不是试图阻止 OOM,因为在某些情况下它可能出于正当原因发生,我只是想确保在应用程序日志文件中清楚

我的问题是:是否有可能在关机钩子中找出由于 OOM 而关闭的进程?

我需要以编程方式并从同一进程执行此操作。

目前最好的方法是查看它是否存在最近日期的 process_.hprof(我知道 pid)的堆转储文件 java_pid_pid 并推断存在 OOM。我想我可以尝试 Runtime.getRuntime().freeMemory() 并在可用内存非常低时报告问题,但不确定这有多可靠,也许当进程关闭时它已经释放了很多内存,该方法以上是我认为最好的。

4

7 回答 7

3

OOM 很棘手,因为如果 JVM 内存不足,它可能会因为抛出新的 OOM 而无法运行异常处理代码。

尝试设置默认的未捕获异常处理程序。它将捕获所有未捕获的异常。

于 2010-11-10T15:34:18.220 回答
2

您可能可以运行另一个进程来监视 OOE 的日志文件(或监视进程是否被终止),然后重新启动该进程。

也许将您的应用程序作为 Unix 守护程序或 Windows 服务会更合适。

但是,用分析工具来调查内存泄漏呢?

jvisualvm 是一个很好的

于 2010-11-10T15:27:25.813 回答
2

您可能想查看该-XX:OnOutOfMemoryError="cmd_with_pid_arg %p"选项(命令字符串类似于-XX:OnError)。

于 2010-11-10T17:53:53.393 回答
1

使用jvisualvmjconsole等监控工具。

于 2010-11-10T15:27:53.377 回答
0

可以(技术上)捕获 OutOfMemoryErrors,但如果没有剩余内存,则不确定您是否能够执行 catch 块中的代码。

也许值得一试(1)捕获 OOM,(2)触发垃圾收集(System.gc())并尝试写一些东西来记录或控制台。不能保证,但它不会破坏任何东西。

于 2010-11-10T15:29:58.557 回答
0

你应该解决问题而不是试图弥补它。

堆转储将向您显示消耗最多内存的对象类型。您应该能够弄清楚这些对象被分配到哪里,或者为什么它们应该被丢弃后仍然存在。

至于您收到的具体错误,请查看这个 SO 问题:Error java.lang.OutOfMemoryError: GC 开销限制超出- 似乎最简单的解决方案是增加堆大小。

于 2010-11-10T16:21:19.320 回答
0

同样,按照其他人或其他分析工具的建议使用 jvisualvm(JDK 6,在 bin 文件夹中)是解决问题而不是处理问题的最佳方法,但假设您将单独调查 OOM 原因并尝试根除它们,我会考虑做以下 POC,(另见 Alois 答案)

运行一个将包装 OOM 抛出进程调用的 Java 进程怎么样?

您可以捕获发送到被调用进程的输出流的任何结果,并查看是否存在可用于识别 OOM 的一致退出代码/堆栈跟踪

我确信还有更多方法,但这在我看来是一个很好的程序化起点

于 2010-11-10T16:36:26.717 回答