101

私は、スタックオーバーフロー例外をスローする方法に対して再帰的な呼び出しを受けました。最初の呼び出しはtry catchブロックで囲まれていますが、例外はキャッチされません。

スタックオーバーフロー例外は特別な方法で動作しますか?例外を正しくキャッチ/処理できますか?

注意:該当する場合:

  • メインスレッドでは例外はスローされません

  • コードが例外をスローしているオブジェクトは、Assembly.LoadFrom(...)によって手動でロードされます。CreateInstance(...)


  • @RichardOD、それはバグだったので私は確実にそのバグを修正します。しかし、問題は別の方法で現れる可能性があり、私はそれを処理したい - Toto
  • 同意すると、スタックオーバーフローは深刻なエラーであり、それが原因でキャッチすることはできません。しないでください捕まる代わりに壊れたコードを修正してください。 - Ian Kemp
  • @RichardOD:デザインしたい場合は再帰降下パーサであり、ホストマシンが実際に必要とするものを超えて深さに人為的な制限を課さない、どうすればよいのでしょうか。私のdruthersを持っていたなら、明示的に捉えることができるStackCritical例外があるでしょう、それはまだ少しのスタックスペースが残っている間に発火するでしょう。実際にスローされるまで無効になり、安全な量のスタックスペースが確保されるまでキャッチできません。 - supercat
  • この質問は役立ちます - スタックオーバーフロー例外が発生した場合、ユニットテストを失敗させたい - しかしNUnitはテストを"無視"に移動します。他の例外があるのと同じように失敗するのではなく、カテゴリ - それをキャッチして実行する必要があります。Assert.Fail代わりに。だから真剣に - 私たちはこれについてどうやって行きますか? - BrainSlugs83

9 답변


94

2.0以降では、StackOverflow例外は以下の状況でしか捕捉できません。

  1. CLRは、ホストがStackOverflow例外の処理を明確に許可しているホスト環境で実行されています。
  2. stackoverflow例外はユーザーコードによってスローされ、実際のスタックオーバーフローの状況によるものではありません(参照


  • 関連するシナリオで捕捉できない場合は、StackoverflowExceptionオブジェクトが存在するのはなぜですか。 - Manu
  • 少なくともいくつかの理由で@Manu。 1)それは1.1でつかまえられるかもしれないということです、そしてそれ故に目的を持っていました。 2)CLRをホストしている場合はまだ検出されている可能性があるので、それは依然として有効な例外タイプです。 - JaredPar
  • 捕捉できない場合...何が起こったのかを説明しているwindowsイベントに、デフォルトでフルスタックトレースが含まれていないのはなぜですか。 - user645280
  • StackOverflowExceptionsをホスト型環境で処理できるようにするにはどうすればよいでしょうか。私が要求しているのは、私がホステッド環境を運営しているためで、アプリプール全体を破壊するという正確な問題を抱えているからです。スレッドを中断して先頭に戻ることができれば、エラーをログに記録して、すべてのアプリケーションプールのスレッドを強制終了することなく続行できます。 - Brain2000
  • Starting with 2.0 ...、私が珍しいのは、彼らがSOを捕まえられないようにしている理由と、それがどのように可能だったか1.1(あなたはあなたのコメントでそれを述べました)? - M.kazem Akhgary

42

正しい方法はオーバーフローを修正することですが、....

あなたは自分自身にもっと大きなスタックを与えることができます: -

using System.Threading;
Thread T = new Thread(threadDelegate, stackSizeInBytes);
T.Start();

System.Diagnostics.StackTrace FrameCountプロパティを使用して、使用したフレームをカウントし、フレーム制限に達したときに独自の例外をスローすることができます。

または、残りのスタックのサイズを計算し、それがしきい値を下回ったときに独自の例外をスローすることができます。

class Program
{
    static int n;
    static int topOfStack;
    const int stackSize = 1000000; // Default?

    // The func is 76 bytes, but we need space to unwind the exception.
    const int spaceRequired = 18*1024; 

    unsafe static void Main(string[] args)
    {
        int var;
        topOfStack = (int)&var;

        n=0;
        recurse();
    }

    unsafe static void recurse()
    {
        int remaining;
        remaining = stackSize - (topOfStack - (int)&remaining);
        if (remaining < spaceRequired)
            throw new Exception("Cheese");
        n++;
        recurse();
    }
}

ただチーズをキャッチ。 ;)


  • Cheese具体的にはほど遠いです。行きますthrow new CheeseException("Gouda"); - C.Evenhuis
  • @ C.Evenhuisゴーダが例外的なチーズであることは間違いありませんが、RollingCheeseException(&quot; Double Gloucester&quot;)である必要があります。cheese-rolling.co.uk - user159335
  • lol、1)修正できません。修正しないと、発生した場所がわからないことがよくあります。2)Stacksizeを大きくしても意味がありません。無限再帰と3)正しい場所でスタックをチェックすることは最初のようです - Firo
  • しかし、私は乳糖不耐症です - redoc

35

上のMSDNページからStackOverflowExceptions:

以前のバージョンの.NETでは   フレームワーク、あなたのアプリケーションは   StackOverflowExceptionオブジェクトをキャッチ   (たとえば、   無制限の再帰)しかし、それは   練習は現在お勧めできません   重要な追加コードが   確実にスタックをキャッチするために必要   例外をオーバーフローさせて続行   プログラムの実行

.NET Frameworkから始める   バージョン2.0、StackOverflowException   オブジェクトをtry-catchでキャッチすることはできません   ブロックし、対応するプロセスは   デフォルトで終了します。その結果、   ユーザーは自分のコードを書くことをお勧めします   スタックを検出して防止する   オーバーフロー。たとえば、   アプリケーションは再帰、使用に依存   カウンタまたは状態条件   再帰ループを終了します。注意   それをホストするアプリケーション   共通言語ランタイム(CLR)は   CLRがアンロードするように指定します。   スタックが置かれているアプリケーションドメイン   オーバーフロー例外が発生し、   対応するプロセスは続行します。にとって   詳細については、を見てください   ICLRPolicyManagerインターフェースおよび   共通言語ランタイムのホスティング


20

何人かのユーザーがすでに言ったように、あなたは例外を捕まえることができません。しかし、それがどこで起こっているのかを見つけるのに苦労しているのであれば、あなたはそれが投げられたときに壊れるようにビジュアルスタジオを設定したくなるかもしれません。

それには、[デバッグ]メニューから[例外設定]を開く必要があります。古いバージョンのVisual Studioでは、これは[デバッグ] - [例外]にあります。新しいバージョンでは、[デバッグ] - [Windows] - [例外設定]にあります。

設定を開いたら、[共通言語ランタイム例外]、[システム]の順に展開し、下にスクロールして[System.StackOverflowException]をオンにします。それからあなたは呼び出しスタックを見て、呼び出しの繰り返しパターンを探すことができます。これにより、スタックオーバーフローの原因となっているコードをどこで修正すればよいかがわかります。


  • VS 2015のデバッグ - 例外はどこにありますか。 - FrenkyB
  • デバッグ - Windows - 例外設定 - Simon

12

上記のように、プロセス状態が破損しているためにシステムによって発生したStackOverflowExceptionをキャッチすることは不可能です。しかし、例外としてイベントとして気付く方法があります。

http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx

.NET Frameworkバージョン4以降では、イベントハンドラーがセキュリティ上重要でHandleProcessCorruptedStateExceptionsAttribute属性を持たない限り、スタックオーバーフローやアクセス違反など、プロセスの状態を破損する例外に対してこのイベントは発生しません。

それにもかかわらず、あなたのアプリケーションはevent-functionを終了した後に終了します(非常に汚い回避策は、このイベントの中でアプリを再起動することでした、そうしないで、決してしないでしょう)。しかし、ログ記録には十分です。

.NET Frameworkバージョン1.0および1.1では、メインアプリケーションスレッド以外のスレッドで発生した未処理の例外はランタイムによってキャッチされるため、アプリケーションは終了しません。したがって、アプリケーションが終了せずにUnhandledExceptionイベントが発生する可能性があります。 .NET Framework Version 2.0以降では、このようなサイレント障害による累積的な影響として、パフォーマンスの低下、データの破損、ロックアップなど、デバッグが困難であったため、子スレッドでの未処理の例外に対するこのバックストップが削除されました。ランタイムが終了しないケースのリストなど、詳細については、管理スレッドでの例外を参照してください。


  • ワオ。これはより多くの支持を得るはずです! - Arsen Zahray

6

CLR 2.0からのはい、スタックオーバーフローは回復不可能な状況と見なされます。だからランタイムはまだプロセスをシャットダウンします。

詳しくはドキュメントをご覧ください。http://msdn.microsoft.com/en-us/library/system.stackoverflowexception.aspx


  • CLR 2.0からStackOverflowExceptionデフォルトでプロセスを終了します。 - Brian Rasmussen
  • いいえ。OOMを捉えることはできますが、場合によってはそうするのが理にかなっているかもしれません。スレッドが消えたという意味がわかりません。スレッドに未処理の例外がある場合、CLRはプロセスを終了します。あなたのスレッドがそのメソッドを完了すると、それはクリーンアップされます。 - Brian Rasmussen

5

できません。 CLRはあなたをさせません。スタックオーバーフローは致命的なエラーであり、回復することはできません。


  • それでは、キャッチ可能ではなく単体テストランナーをクラッシュさせるのであれば、どうやって単体テストをこの例外に対して失敗させるのでしょうか。 - BrainSlugs83
  • @ BrainSlugs83。愚かな考えだからだ。とにかくあなたのコードがStackOverflowExceptionで失敗した場合、なぜあなたはテストしているのですか? CLRが変更されてより深いスタックを処理できるようになった場合はどうなりますか?あなたがあなたのユニットテストされた関数をすでに深くネストされたスタックを持っているどこかに呼ぶとどうなりますか?テストできないことがあるようです。あなたが手動でそれを投げようとしているならば、タスクのためにより良い例外を選びなさい。 - Matthew Scharley

5

ほとんどの投稿が説明しているようにあなたはできません、私は別の分野を加えてみましょう:

多くのWebサイトでは、これを回避する方法は別のAppDomainを使用することで、ドメインがアンロードされると言われています。 CLRのデフォルトの動作によってKillProcessイベントが発生し、デフォルトのAppDomainがダウンするため、これは絶対に間違っています(CLRをホストしている場合を除く)。


3

それは不可能であり、そして正当な理由のために(一つには、それらすべてのキャッチについて考える(例外){})。

スタックオーバーフロー後も実行を継続したい場合は、別のAppDomainで危険なコードを実行してください。元のドメインに影響を与えることなく、オーバーフロー時に現在のAppDomainを終了するようにCLRポリシーを設定できます。


  • &quot;キャッチ&quot; catchステートメントが実行できるようになるまでにシステムが2つのスタックスペースを使用しようとしたことによる影響がロールバックされるため、ステートメントは実際には問題になりません。スタックオーバーフローの例外をキャッチするのが危険である必要はないという理由はありません。そのような例外を捕捉できない理由は、それらが安全に捕捉されるようにするには、追加のオーバーヘッドを追加する必要があるためです。すべてオーバーフローしない場合でも、スタックを使用するコード。 - supercat
  • ある時点で、その声明はよく考えられていません。 Stackoverflowを見つけられない場合は、実稼働環境でどこで起こったのかわからないことがあります。 - Offler

リンクされた質問


関連する質問

最近の質問