java.lang.OutOfMemoryError をキャッチしますか? 質問する

java.lang.OutOfMemoryError をキャッチしますか? 質問する

ドキュメンテーションfor はjava.lang.Errorこう言います:

ErrorはThrowableのサブクラスであり、適切なアプリケーションがキャッチしようとすべきではない重大な問題を示します。

しかし、 はjava.lang.Errorのサブクラスなのでjava.lang.Throwable、このタイプの Throwable をキャッチできます。

この種の例外をキャッチするのはなぜ良い考えではないのかは理解しています。私が理解している限りでは、キャッチすることにした場合、キャッチ ハンドラはそれ自体でメモリを割り当てるべきではありません。そうしないと、OutOfMemoryError再度スローされます。

そこで私の質問は次のとおりです。

  1. java.lang.OutOfMemoryErrorキャッチングがよいアイデアになるような現実的なシナリオはありますか?
  2. catch することにした場合java.lang.OutOfMemoryError、catch ハンドラがそれ自体でメモリを割り当てないようにするにはどうすればよいでしょうか (ツールやベスト プラクティスはありますか)?

ベストアンサー1

エラーをキャッチしたいシナリオは数多くありますが、私の経験では (Windows および Solaris JVM の場合)、 JVM の死を告げるエラーOutOfMemoryErrorはごくまれです。OutOfMemoryError

エラーをキャッチする正当な理由は 1 つだけです。OutOfMemoryErrorそれは、正常に終了し、リソースを正常に解放し、失敗の理由をできる限りログに記録することです (まだそれが可能な場合)。

一般的に、これはOutOfMemoryErrorヒープの残りのリソースでは満たせないブロック メモリ割り当てが原因で発生します。

がスローされると、Errorヒープには割り当てが失敗する前と同じ量の割り当て済みオブジェクトが含まれるため、この時点でランタイム オブジェクトへの参照を削除して、クリーンアップに必要なメモリをさらに解放する必要があります。このような場合、続行できる可能性もありますが、JVM が修復可能な状態であることを 100% 確信することはできないため、これは絶対にお勧めできません。

OutOfMemoryErrorcatch ブロックで JVM のメモリが不足していることを意味しないデモンストレーション:

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) {}あらゆる場所を網羅したり、そのような無意味なことをしたりしないでください。

おすすめ記事