检测内存不足错误

问题描述 投票:0回答:5

我想为我的系统提供一种检测是否发生内存不足异常的方法。此练习的目的是通过 JMX 公开此标志并采取相应措施(例如,通过在监控系统上配置相关警报),否则这些错误几天内都不会被注意到。

简单的方法是为每个线程设置一个未捕获的异常处理程序,并检查引发的异常是否是

OutOfMemoryError
的实例并设置相关标志。然而,由于以下原因,这种方法并不现实:

  • 异常可能发生在任何地方,包括第三方库。我无法阻止他们抓住
    Throwable
    并将其据为己有。
  • 库可以生成自己的线程,但我无法为这些线程强制执行未捕获的异常处理程序。

我看到的一种可能的场景是字节码操作(例如,在

OutOfMemoryError
之上附加某种方面),但是我不确定这是否是正确的方法,或者这通常是否可行。

我们启用了

-XX:+HeapDumpOnOutOfMemoryError
,但我不认为这是解决此问题的方法,因为它是为其他目的而设计的 - 并且在发生这种情况时它不提供 Java 回调。

有人做过吗?您将如何解决它或建议解决它?欢迎任何想法。

java exception out-of-memory
5个回答
6
投票

您可以使用内存不足警告系统;这个OutOfMemoryError警告系统可以是一个灵感。您可以配置一个侦听器,在超出某个内存阈值(例如 80%)后调用该侦听器 - 您可以使用此调用来开始采取纠正措施。

我们使用类似的东西,当组件的内存阈值达到80%时,我们暂停组件的服务,并开始清理操作;仅当使用的内存低于另一个可配置值阈值时,该组件才会返回。


3
投票

有一篇基于 帖子文章,Scorpion 已经给出了链接。

该技术再次基于使用 MemoryPoolMXBean 并订阅“超出内存阈值”事件,但与原始帖子中描述的内容略有不同。

作者指出,当您订阅简单的“超出内存阈值”事件时,有可能出现“误报”。想象一下当内存消耗高于阈值时的情况,但很快就会执行垃圾收集,然后释放大量内存。事实上,这种情况在现实世界的应用中很常见。

幸运的是,还有另一个阈值,“收集使用阈值”,以及一个相应的事件,该事件是在垃圾收集后根据内存消耗立即触发的。当您收到该事件时,您可以更加确信自己的内存不足。


0
投票

我们启用了 -XX:+HeapDumpOnOutOfMemoryError,但我没有看到这个 作为这个问题的解决方案,因为它是为其他东西而设计的 - 当发生这种情况时,它不提供 Java 回调。

这个标志应该就是您所需要的。 将生成的堆转储文件的输出目录设置在您定期检查的某个已知位置。 回调对你来说没有任何用处。 如果内存不足,则无法保证回调代码有足够的内存执行! 您所能做的就是收集数据并使用外部程序来分析内存不足的原因。 任何在过程中恢复的尝试都可能会产生更大的问题。

字节码检测是可能的,但很难。 HPjmeter 监控工具能够预测未来的 OOM(带有警告)——但仅限于基于 HP-UX/Itanium 的系统。 您可以专用一个守护线程来计算进程中使用的内存,并在超出时触发警报,但实际上您并没有解决问题。


0
投票

您可以使用静态 Thread.setDefaultUncaughtExceptionHandler. 捕获任何和所有

 未捕获 
异常。当然,如果有人捕获所有 Throwables,这也无济于事。 (我不认为任何事情都会发生,尽管对于 OOME,我怀疑你会得到级联效应,直到有问题的
try
块之外的东西爆炸。)希望线程能够释放足够的内存,以便异常处理程序能够工作;当您尝试处理 OOM 错误时,它们确实会成倍增加。


0
投票

我选择了一个稍微不同的选择。在我们的swing应用程序中,outofmemoryerror可能是由第三方库抛出的,也可能是在其他地方抛出的,但无论在哪里,最终似乎总是将OutOfMemoryError打印到System.err,因此我编写了以下代码。 这使得应用程序中通常不可见的 JPanel 在发生 OutofMemoryError 时显示,向用户解释发生了什么,这比应用程序只是挂起/崩溃要好得多。 它还将 System.err 打印到文件和控制台。

private void initErrorOutput() {
    try {
        File f = new File("errors.log");
        boolean append = f.exists() && f.length() < 4*1024*1024;
        FileOutputStream out = new FileOutputStream(f, append);
        PrintStream old = System.err;
        MyErrorStream mes = new MyErrorStream(out,old);
        System.setErr(mes);
    }catch(Exception ex) {
        ex.printStackTrace();
    }
}
private class MyErrorStream extends java.io.PrintStream{
    PrintStream console;
    private MyErrorStream(java.io.OutputStream out, PrintStream old) {
        super(out);
        console = old;
    }
    private void check(Object o) {
        if (o == null) return;
        if (o instanceof char[]) o = new String((char[])o);
        String s = o.toString();
        if (s.contains("java.lang.OutOfMemoryError")) {
            System.out.println("\033[31m"+s+"\033[0m");
            outofmemoryPanel.setVisible(true);
        }
    }
    @Override
    public void println(Object x) {
        console.println(x);
        super.println(x);
        check(x);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.