StackOverflowErrorから回復できるのはなぜですか?


100

StackOverflowErrorJavaでa が発生した後でも実行を継続できることに驚いています。

私はそれStackOverflowErrorがクラスErrorのサブクラスであることを知っています。Errorクラスは、「合理的なアプリケーションがキャッチしようとしてはならない深刻な問題を示すThrowableのサブクラス」としてデクリメントされています。

StackOverflowErrorのようなエラーをキャッチすることは実際には許可されており、それを行わないことはプログラマーの判断に委ねられているため、これは規則よりも推奨事項のように聞こえます。そして、このコードをテストしたところ、正常に終了しました。

public class Test
{
    public static void main(String[] args)
    {
        try {
            foo();
        } catch (StackOverflowError e) {
            bar();
        }
        System.out.println("normal termination");
    }

    private static void foo() {
        System.out.println("foo");
        foo();
    }

    private static void bar() {
        System.out.println("bar");
    }
}

どうすればいいの?StackOverflowErrorがスローされる頃には、スタックがいっぱいになっていて、別の関数を呼び出す余地がないと思います。エラー処理ブロックは別のスタックで実行されていますか、またはここで何が起こっていますか?



57
StackOverflowで常にエラーが発生します。私が戻ってくるのを止めることはありません。

10
Yo dawg ...スタックオーバーフローが好きだと聞いたので、stackoverflow.comにスタックオーバーフローを配置しました。
Pierre Henry 14

最新のアーキテクチャでは、フレームポインタを使用して、スタックの巻き戻しを容易にします。そのためのコード+コンテキストをスタックから動的に割り当てる必要がない限り、問題は発生しません。
RBarryYoung

回答:


119

スタックがオーバーフローしStackOverflowErrorてスローされると、通常の例外処理でスタックがほどかれます。スタックをほどくとは、

  • 現在アクティブな関数の実行を中止します
  • スタックフレームを削除し、呼び出し元の関数に進みます
  • 呼び出し元の実行を中止する
  • スタックフレームを削除し、呼び出し元の関数に進みます
  • 等々...

...例外がキャッチされるまで。これは正常(実際には必要)であり、どの例外がスローされるか、およびその理由とは無関係です。への最初の呼び出し以外で例外をキャッチしたので、スタックを埋めたfoo()何千ものfooスタックフレームがすべて解かれ、ほとんどのスタックは自由に再び使用できます。


1
@fge自由に編集して、段落の区切りを検討しましたが、見栄えの良い場所が見つかりませんでした。

1
箇条書きを使用できます...私は他の人の投稿を編集することに消極的です;)
fge

1
重要なのは、最も内側fooが未定義の状態で終了しているため、接触した可能性のあるオブジェクトはすべて壊れていると見なす必要があることです。スタックオーバーフローが発生した関数がわからないtryため、それをキャッチしたブロックの子孫である必要があるだけで、そこから到達可能な任意のメソッドによって変更される可能性のあるオブジェクトが疑われます。通常、何が起こったかを見つけて修正しようとする価値はありません。
Simon Richter

2
@delnan、私は答えが不完全だと思いますが、これがなぜ悪い考えであるのか詳細にも触れません。明示的にスローされた例外との違いは、Error例外セーフなコードを記述した場合でも、sを予期できないことです。
Simon Richter

1
@SimonRichterいいえ、質問はかなり具体的です。それはsを扱うことではありませんError。OPはについてのみStackOverflowError尋ねていますが、このエラーの処理について特定のことを求めています。このエラーがキャッチされたときにメソッド呼び出し失敗しないようにするにはどうすればよいですか。
バクリウ14年

23

StackOverflowErrorがスローされると、スタックがいっぱいになります。ただし、それがキャッチされると、それらのfoo呼び出しはすべてスタックからポップされます。barスタックがfoosでオーバーフローしなくなったため、通常どおり実行できます。(私がJLSがこのようなスタックオーバーフローから回復できることを保証しているとは思わないことに注意してください。)


12

StackOverFlowが発生すると、JVMはキャッチにポップダウンし、スタックを解放します。

あなたの例では、スタックされたすべてのfooを取り除きます。


8

スタックが実際にはオーバーフローしないからです。より適切な名前はAttemptToOverflowStackです。基本的には、スタックに十分な空き領域がないため、スタックフレームを調整する最後の試行が失敗することを意味します。スタックには実際には多くのスペースが残っている可能性がありますが、十分なスペースではありません。そのため、呼び出しの成功(通常はメソッドの呼び出し)に依存する操作は実行されず、プログラムがその事実を処理するだけです。つまり、他の例外とまったく同じです。実際、呼び出しを行っている関数で例外をキャッチできます。


1
これを行う場合は、例外ハンドラーが利用可能なよりも多くのスタックスペースを必要としないように注意してください!
Vince

2

たように、既に回答されて、コードを実行することが可能であり、特にキャッチした後、関数を呼び出すためにStackOverflowErrorJVMの手続きを扱う通常の例外が間スタック巻き戻しているためthrowcatch、使用するスタック領域を解放、ポイントを。そして、あなたの実験はそれが事実であることを確認します。

しかし、それはし、一般的には、可能であると言ってまったく同じではありません回復するからStackOverflowError

AはStackOverflowError-A IS VirtualMachineError-IS AN、 Error。ご指摘のとおり、Javaは次のことについて漠然としたアドバイスを提供しますError

合理的なアプリケーションがキャッチしようとしてはならない深刻な問題を示します

あなたは、合理的、と結論づけるべきで引くような音はError、いくつかの状況であるかもしれない[OK]を。1つの実験を実行しても、何かが一般的に安全であることを示すものではないことに注意してください。Java言語のルールと使用するクラスの仕様だけがそれを行うことができます。A VirtualMachineErrorは、Java言語仕様Java仮想マシン仕様がこの例外のセマンティクスに関する情報を提供するため、例外の特別なクラスです。特に、後者は言う

Java Virtual Machine実装は、VirtualMethodError内部エラーまたはリソースの制限により、この章で説明されているセマンティクスを実装できない場合、クラスのサブクラスのインスタンスであるオブジェクトをスローします。この仕様では、内部エラーまたはリソースの制限が発生する可能性のある場所を予測することはできず、いつ報告できるかを正確に規定していません。したがって、VirtualMethodError以下で定義されているサブクラスは、Java仮想マシンの操作中にいつでもスローされる可能性があります。

...

  • StackOverflowError:Java仮想マシンの実装がスレッドのスタックスペースを使い果たしました。これは、通常、実行中のプログラムでの障害の結果として、スレッドが無限の再帰呼び出しを行っているためです。

重要な問題は、a StackOverflowErrorがスローされる場所またはタイミングを「予測できない」ことです。スローされない場所についての保証はありません。たとえば、メソッドへのエントリ時にスローされることに依存することはできません。メソッド内のある時点スローされる可能性があります。

この予測不可能性は潜在的に悲惨です。メソッド内でスローできるため、クラスが1つの「アトミック」操作であると見なす一連の操作の途中でスローされ、オブジェクトが部分的に変更された、矛盾した状態のままになる可能性があります。矛盾した状態にあるオブジェクトを使用すると、任意のそのオブジェクトを使用しようとすると、誤った行動につながる可能性があります。すべての実際的なケースでは、どのオブジェクトが不整合な状態にあるか知ることができないため、信頼できるオブジェクトはないと想定する必要があります。任意の回復動作や例外がキャッチされた後に継続しようとするとは、したがって、誤った振る舞いを持つことができます。行うための唯一の安全な事はすることはありませんキャッチStackOverflowError、しかしむしろプログラムを終了させる。(実際には、トラブルシューティングを支援するためにいくつかのエラーロギングを試みる可能性がありますが、そのロギングが正しく動作することに依存することはできません)。つまり、から確実に回復することはできませんStackOverflowError

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.