132

スタック オーバーフロー例外をスローするメソッドへの再帰呼び出しがあります。最初の呼び出しは try catch ブロックで囲まれていますが、例外はキャッチされません。

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

関連するかどうかはわかりませんが、追加情報:

  • メインスレッドで例外がスローされない

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

4

9 に答える 9

118

2.0以降、StackOverflow例外は次の状況でのみキャッチできます。

  1. CLRは、ホストされた環境で実行されています*ホストがStackOverflow例外の処理を明確に許可している場合
  2. stackoverflow例外は、実際のスタックオーバーフローの状況ではなく、ユーザーコードによってスローされます(リファレンス

*「私のコードはCLRをホストし、CLRのオプションを構成する」のように「ホストされた環境」であり、「私のコードは共有ホスティングで実行される」ではありません

于 2009-10-21T07:20:08.173 に答える
51

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

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

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();
    }
}

チーズをキャッチするだけです。;)

于 2009-10-21T11:33:21.820 に答える
44

StackOverflowExceptionのMSDNページから:

以前のバージョンの.NETFrameworkでは、アプリケーションがStackOverflowExceptionオブジェクトをキャッチする可能性がありました(たとえば、無制限の再帰から回復するため)。ただし、スタックオーバーフローの例外を確実にキャッチしてプログラムの実行を継続するには、かなりの追加コードが必要になるため、現在この方法は推奨されていません。

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

于 2009-10-21T07:19:08.287 に答える
29

何人かのユーザーがすでに言っているように、例外をキャッチすることはできません。ただし、発生している場所を見つけるのに苦労している場合は、Visual Studio がスローされたときに中断するように構成することをお勧めします。

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

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

于 2009-10-21T08:29:18.347 に答える
16

上で何度か説明したように、プロセス状態の破損が原因でシステムによって発生した StackOverflowException をキャッチすることはできません。ただし、例外をイベントとして通知する方法があります。

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

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

それにもかかわらず、あなたのアプリケーションはイベント関数を終了した後に終了します (非常に汚い回避策は、このイベント内でアプリを再起動することでした。しかし、ロギングには十分です!

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

于 2011-07-28T09:33:27.457 に答える
6

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

詳細については、ドキュメントhttp://msdn.microsoft.com/en-us/library/system.stackoverflowexception.aspxを参照してください。

于 2009-10-21T07:18:50.127 に答える
5

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

于 2009-10-21T07:19:35.383 に答える
5

ほとんどの投稿で説明されているように、できません。別の領域を追加させてください。

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

于 2010-02-11T08:39:26.590 に答える
3

それは不可能であり、正当な理由があります(1つには、これらすべてのcatch(Exception){}について考えてください)。

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

于 2009-10-21T07:33:03.717 に答える