JavaでStackOverflowErrorをキャッチしても大丈夫ですか?


27

以前はそうではないと思っていましたが、昨日はそうしなければなりませんでした。Akka(JVMのアクターシステム実装)を使用して非同期ジョブを処理するアプリケーションです。アクターの1人がPDF操作を実行しますが、ライブラリーにはバグがあるため、たまに死にStackOverflowErrorます。

2番目の側面は、JVMの致命的なエラー(StackOverflowErrorなど)がキャッチされた場合、Akkaがアクターシステム全体をシャットダウンするように構成されていることです。

3番目の側面は、このアクターシステムがWebアプリ内に埋め込まれている(WTFのような、レガシー、理由のため)ため、アクターシステムがシャットダウンされても、Webアプリはそうではありません。最終的な効果はStackOverflowError、ジョブ処理アプリケーションで空のWebアプリになることです。

迅速な修正として、StackOverflowErrorアクターシステムのスレッドプールが破棄されないように、スローされているものをキャッチする必要がありました。これは、特にこのようなコンテキストでそのようなエラーをキャッチしてもいいかもしれないと思うようになりましたか?任意のタスクを処理するスレッドプールがある場合 とは異なり、アプリケーションが一貫性のない状態のままOutOfMemoryErrorになることを想像することはできませんStackOverflowError。スタックはこのようなエラーの後にクリアされるため、計算は正常に続行できます。しかし、おそらく重要なものが欠けています。

また、最初にエラーを修正するのはすべてです(実際、数日前にこのアプリでSOEを修正済みです)ある種の状況が発生する可能性があります。

をキャッチするのStackOverflowErrorではなく、JVMプロセスを再起動して、そのジョブを失敗としてマークし、ビジネスを続行する方がよいのはなぜですか?

国営企業を捕まえない理由はありますか?「ベストプラクティス」を除きます。これは、何も言えないあいまいな用語です。


1
別のオプションは、JVMで利用可能なスタック領域を増やすことです
ラチェットフリーク

3
@ratchetfreak:StackOverflowExceptionsは通常、メソッド呼び出しの終了しないチェーンによるものです。スタックスペースを増やすと、新しいスレッドのメモリコストが増えますが、利益はありません。
ジョミナル

1
入力が非常に大きいため、少なくとも1つのSOEが正当でした。残念ながら、再帰的な実装(Javaの正規表現実装)でそれを処理することはあまり良い考えではありませんでした。とにかく、計算が終了することが保証されている場合でも、新しいスタックサイズが他の計算に十分な大きさかどうかはわかりません。
イオヌG.スタン

2
これをStaに移行しないでください...ああ、ちょっと...気にしないでください。 :-)
Blrfl

バギーライブラリについて。OSに強制終了させるには、そのPDF操作関数を独自のプロセスに実際に移行する必要があります。
エスベンスコフペダーセン14

回答:


44

一般的なルールとして、何かをすることが絶対に決して許されず、それについて合意があった場合、言語実装者はそれを許可しなかったでしょう。そのような満場一致で明確な格言はほとんどありません。(幸いなことに、それが私たち人間のプログラマーの仕事を続けているからです!)

このエラーをキャッチすることがあなたにとって最良のオプションである状況を見つけたかのように見えます:それはあなたのアプリケーションを動作させますが、他のすべての代替は動作しません、そしてそれは最終的に重要です。すべての「ベストプラクティス」は、多くの場合の長い経験の単なる要約であり、通常は時間を節約するために特定のケースの詳細な分析の代わりに使用できます。あなたの場合、あなたはすでに特定の分析を行っており、異なる結果を得ています。おめでとうございます、あなたは独立した思考ができます!

(そうは言っても、確かに、スタックオーバーフローによってメモリ不足のようにアプリケーションが不整合になる場合があります。一部のオブジェクトが構築され、ネストされた内部メソッド呼び出しの助けを借りて初期化されると想像してください。割り当てが失敗したかのように、可能性のない状態になっている可能性が非常に高い場合があります。しかし、それはあなたのソリューションがまだ最高のものではないという意味ではありません。


3
ありがとう。.NETがStackOverflowExceptionキャッチ不可能な例外を作成したことを発見した後、私の疑問はいくらか強化されました。別のプラットフォームですが、理由があるのではないかと思いました。また、オブジェクトの初期化に関するあなたのポイントはスポットオンです。これにより、このSOEをいくつかの抽象化レイヤーの下にキャッチし、「間違った」SOEをキャッチしないようにする必要があると考えるようになります。
イオヌG.スタン

14
+1:ベストプラクティスには、「ベスト」である理由とコンテキストを常に説明する必要があります。これにより、特定のケースに当てはまるかどうかを判断できます。
マイケルボルグ

situations hereする必要がありますsituations where
セルビー

2

ここにJVM固有のリスクがあるかどうかはわかりませんが、全体的にはかなり賢明なようです。

たとえば、単純なクイックソートのようなlog(n)、典型的なケースではスタックの深さを持つ再帰アルゴリズムがありますが、最悪の場合n、スタックを爆破できる深さまで低下します。

最悪のケースはまれであり、部分的にソートされたセットでソートを再開すると再び発生する可能性は低いため、エラーが発生したり強制終了したりするのを防ぐのではなく、スタックオーバーフロー例外が発生したときにキャッチして作業を再開することは理にかなっていますアプリケーション全体。

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