一尘不染

捕获java.lang.OutOfMemoryError?

java

错误是Throwable的子类,它指示严重的问题,即合理的应用程序不应尝试捕获

但作为java.lang.Error的子类java.lang.Throwable,我可以捕获这种Throwable类型。

我了解为什么捕获这种异常不是一个好主意。据我了解,如果我们决定捕获它,捕获处理程序不应自行分配任何内存。否则OutOfMemoryError会再次抛出。

所以,我的问题是:

  1. 捕捞java.lang.OutOfMemoryError可能是个好主意吗?
  2. 如果我们决定进行catch java.lang.OutOfMemoryError,如何确保catch处理程序本身不会分配任何内存(任何工具或最佳实践)?

阅读 385

收藏
2020-02-29

共1个答案

一尘不染

我同意和不同意这里的大多数答复。

OutOfMemoryError根据我的经验(在Windows和Solaris JVM上),你可能希望在许多情况下抓住一个机会,而对JVM OutOfMemoryError的丧钟很少见。

捕获OutOfMemoryError故障只有一个很好的理由,那就是正常关闭,干净地释放资源并尽可能地记录故障原因(如果仍然可以这样做)。

通常,OutOfMemoryError发生这种情况的原因是块内存分配无法用堆的其余资源满足。

当Error被抛出堆载分配的对象是不成功的分配之前相同数量的,现在是下降到运行时间对象以释放可能需要进行清理更加内存引用的时间。在这些情况下,甚至有可能继续执行操作,但这绝对不是一个好主意,因为你永远无法100%确定JVM处于可修复状态。

演示OutOfMemoryError并不意味着JVM的catch块中的内存不足:

private static final int MEGABYTE = (1024*1024);
public static void runOutOfMemory() {
    MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
    for (int i=1; i <= 100; i++) {
        try {
            byte[] bytes = new byte[MEGABYTE*500];
        } catch (Exception e) {
            e.printStackTrace();
        } catch (OutOfMemoryError e) {
            MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
            long maxMemory = heapUsage.getMax() / MEGABYTE;
            long usedMemory = heapUsage.getUsed() / MEGABYTE;
            System.out.println(i+ " : Memory Use :" + usedMemory + "M/" + maxMemory + "M");
        }
    }
}

此代码的输出:

1 : Memory Use :0M/247M
..
..
..
98 : Memory Use :0M/247M
99 : Memory Use :0M/247M
100 : Memory Use :0M/247M

如果运行关键任务,通常会捕获Error,将其记录到syserr中,然后使用选择的日志记录框架对其进行记录,然后继续释放资源并以一种简洁的方式关闭它。可能发生的最坏情况是什么?无论如何,JVM都快要死了(或已经死了),并且抓住它Error至少有清除的机会。

需要注意的是,你必须仅在可能进行清理的地方针对捕获这些类型的错误。不要catch(Throwable t) {}到处遮盖或胡说八道。

2020-02-29