web-dev-qa-db-ja.com

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

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

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

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

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

また、私は最初からエラーを修正するためにすべてを担当していることに注意してください(実際、私は数日前にこの同じアプリですでにSOEを修正しています)。ある種の状況が発生する可能性があります。

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

SOEを絶対に受け取らない説得力のある理由はありますか? 「ベストプラクティス」を除いて、何もわからない漠然とした用語です。

27
Ionuț G. Stan

一般的なルールとして、もしそれが絶対に絶対に、決して何かをするのに受け入れ可能であり、それについて合意があった場合、言語実装者はそれを許可しなかっただろう。そのような満場一致で明確な格言はほとんどありません。 (幸い、それが私たち人間のプログラマーを仕事に引き留めている理由です!)

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

(とはいえ、スタックオーバーフローがメモリ不足のようにアプリケーションの一貫性を失わせる可能性がある状況は確かにあります。あるオブジェクトが作成され、ネストされた内部メソッド呼び出しの助けを借りて初期化されることを想像してください-それらの1つがスローすると、オブジェクト割り当てが失敗したかのように、可能ではないはずの状態になっている可能性がありますが、それでもソリューションが最良のソリューションであるとは限りません。)

44
Kilian Foth

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

たとえば、一般的なケースではlog(n)スタックの深さを持つ素朴なクイックソートのような再帰的なアルゴリズムがありますが、最悪の場合、スタックを破壊する可能性がある深さnに低下します。

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

2
Kornel