【问题标题】:Is it such a bad idea to capture OutOfMemoryError? [duplicate]捕获 OutOfMemoryError 是不是一个坏主意? [复制]
【发布时间】:2011-11-13 03:42:22
【问题描述】:

可能重复:
Catching java.lang.OutOfMemoryError

OutOfMemoryError 是:

当 Java 虚拟机无法分配对象时抛出,因为 内存不足,无法再提供内存 垃圾收集器

Java 说:

错误是 Throwable 的子类,表示存在严重问题 一个合理的应用程序不应该试图捕捉。大多数这样的 错误是异常情况。

这感觉就像在听:

如果您溺水,请保持理智:您不应该尝试向上游泳 让你的头保持在水面之上。死亡通常是由于 异常情况。

让我们想象一个正在运行服务的场景。由于某种原因,同一服务器上的另一个应用程序正在消耗大量内存,从而导致您的服务出现意外的 OOM。尝试减少此服务的内存消耗以保持对用户可用是不是一个坏主意?

或者在抛出 OOM 之后,JVM 级别是否发生了更根本的事情,阻止了这种解决方案的实施?

【问题讨论】:

  • @aix 我可以通过将某些数据结构设置为 null 来减少对某些数据结构的引用,即使我没有正确保存它们,但在戏剧性的情况下仍然可以接受。
  • @dogbane 您的参考资料没有回答我的问题,这个问题不是重复的。
  • 一个更好的类比是:您驾驶着一辆着火的汽车。不要试图继续到达目的地。拉到坚硬的肩膀上。
  • 如果您的服务可以选择在 OOM 之后使用更少的内存,那么为什么不总是使用更少的内存来避免 OOM?
  • @JVerstry 在这种情况下,飞机正俯冲入大西洋,而您距离水面仅 100 米,两个引擎都发生故障。你对此无能为力。让它沉入水中!

标签: java try-catch out-of-memory


【解决方案1】:

正如你所引用的

当 Java 虚拟机无法分配对象时抛出,因为 内存不足,无法再提供内存 垃圾收集器

到那时你就完蛋了。该描述意味着 Java/JVM 无法获得足够的资源来运行,如果这是真的,那么执行更多的 Java 代码来解决问题本身就是有问题的。

一个很好的类比是你的车没油了,你想通过踩油门来解决这个问题。

更好的解决方案是进行容量规划并确保

1) 您的服务器有足够的内存来完成它们的工作
2) 在您的服务器上运行的服务在规范内执行,并且不会消耗超过一定数量的资源。

【讨论】:

  • “JVM 不再正常运行”或者没有资源可以正常运行?
  • 真的是第二个,编辑了我的答案。
  • 我也是这么想的,因此,(至少)尝试挽救局面并非完全不可能或不合理。
  • 是的。你的油箱是空的。你需要加更多的油,而不是踩油门
【解决方案2】:

这里的问题是OOM是一个正常情况下不应该发生的错误。通过捕获它并尝试释放内存,您可能会掩盖其他地方的某种泄漏或意外行为。

如果确实出现 OOM,可能是因为您没有将 JVM 配置为使用更多内存。

【讨论】:

  • 同意,但我可以在释放内存并自己调用 gc 后记录该问题。这并非不可能。
  • 如果您可以修复它,并且您知道错误发生的原因并且它是合法的,那么请务必这样做。但大多数情况下,当您遇到 OOM 时,您不会知道并且很难恢复,因为您会发现一旦您的 VM 内存不足,您可以做的事情非常有限。跨度>
【解决方案3】:

这是个坏主意。主要是因为 OutOfMemoryErrorError 而不是 Exception - 错误“表示合理的应用程序不应尝试捕获的严重问题。”

相反,请根据PDF 中提供的信息分析您可能的情况并应用修复程序

【讨论】:

  • 好的,但是如果你能修复飞机的飞行以避免坠机呢?有什么理由不这样做吗?这是我的问题...
  • 伙计,真是个比喻!因此,飞机失事是由于某种情况而发生的,而这种情况在大多数情况下都是不受人为控制的。为此,定义了紧急程序,以便仍然可以拯救一些灵魂。同样,如果应用程序非常关键,应用程序应该有早期警告,并且应该有一个恢复过程 - 如果合理的话。如果您要赶上OutOfMemoryError,您会在哪里赶上?大多数时候,当你抓住它时,你无能为力。就像一架飞机在大西洋中部坠毁;即使你有降落伞,幸存的机会也是 0
【解决方案4】:

您无法真正从 OOM 中恢复。

然而,尝试捕捉任何东西是有原因的——当我们在一个我不再从事的项目中这样做时,“可投掷”派告诉我——其中一个原因是:尝试记录发生的事情。因为如果您不知道发生了什么,就很难弄清楚如何让软件恢复并运行。

还有一个很大的“但是”原因:它通常不会起作用。

错误通常无法从运行的代码中修复,这就是存在差异的原因。

【讨论】:

    【解决方案5】:

    没用。因为在捕获错误的那一刻,您的堆内存可能非常不足,以至于任何新对象的创建都可能引发新的 OOME。在接球过程中有如此小的回旋余地意味着您唯一可以采取的行动就是退出。

    测试这个 sn-p,然后告诉我你的输出是什么:

          import java.util.LinkedList;
          import java.util.List;
    
          public class OOMErrorTest {
    
    
            public static void main(String[] args) {
                List<Long> ll = new LinkedList<Long>();
    
                try {
                    long l = 0;
                    while(true){
                        ll.add(new Long(l++));
                    }
                } catch(OutOfMemoryError oome){         
                    System.out.println("Error catched!!");
                    System.out.println("size:" +ll.size());
                }
                System.out.println("Test finished");
            }
    
          }
    

    但严格来说,是的,这些都是可以捕获的。

    【讨论】:

    猜你喜欢
    • 2014-08-23
    • 2019-02-01
    • 2011-02-03
    • 1970-01-01
    • 2010-11-29
    • 1970-01-01
    • 1970-01-01
    • 2012-01-21
    • 2011-11-29
    相关资源
    最近更新 更多