8

StackOverflowException私が知る限り、キャッチ不能であるべき根本的な理由はありません。それでもそうです。

スレッドのスタックには最大サイズがあり、ビット数に応じてデフォルトで 1MB または 4MB になりますが、このスペースは予約されているだけです。何かが実際に多くのスタックを必要とするまで、コミットされません (したがって、仮想アドレス空間のみを使用します)。

私の知る限り、キャッチできない理由の背後にある基本的な考え方は、それまでにすべてのスタックを使い果たしたため、スタック外の状態用に非常に注意深く設計されたコード以外は実際には何も実行できないということです。しかし、これには明らかな解決策が必要です。すべてのスタック スペースがなくなるStackOverflowException 前にスローするのです。

なぜこれが行われないのですか?私が考えることができる唯一のリモートで賢明な理由は、これが消費する余分な仮想アドレス空間(実際のメモリ使用量ではありません!) が、この例外をキャッチ可能にするメリットに値しないと判断されたことです。

私が考慮していない他の懸念事項はありますか?

SOでこれに対処するほとんどの回答は、これを適切に機能させることは不可能であることを暗示しているように思われるため、質問する必要があると感じています.NETがそれらをキャッチできない理由です。


キャッチ可能なバリアントの正確な実装の詳細は重要ではないように見えますが、ここに 1 つのアイデアを示します。まず、デフォルトの予約済みスタック サイズを 2 倍にしますが、1MB の使用量でトリガーするように例外を設定します。ここまでは、既存のアプローチとまったく同じです。ただし、しきい値に達したら、キャッチできない例外をスローする代わりに、しきい値を 1.5MB に増やしながら、キャッチ可能な例外をスローします。例外がキャッチされ、再度制限を超えた場合は、1.75MB に設定します。次に1.875MB。ネストされ処理された各例外は、キャッチできないバリアントをスローする必要があるほど 2MB に近づくまで、処理される余分なスタック スペースの量が減少し続けます。

StackOverflowException の処理が成功した後にしきい値を元に戻すには、書き込み時に失敗するために吹き飛ばしたスタック サイズの半分 (最初のインスタンスでは 0.5MB) でメモリ ページをマークしましょう。障害ハンドラーは、スタック使用量がそのレベルに戻ったときにほぼ排他的にトリガーされるため、コストはかかりません。ハンドラーは実際のスタック サイズをチェックし、適切な場合はしきい値を元に戻します。

4

1 に答える 1

4

1.1 から 2.0 に変更された理由はわかりません (Eric がいつかコメントしてくれることを願っています)。

public bool Count(int64 i)
{
    try
    {
        // somewhere in here a stack overflow exception is thrown
        if(i < int64.MaxValue)
            return Count(i+1);
        else
            return true;
    } Catch(StackOverflowException soEx)
    {
        HandleError(soEx);
    }
}

public void HandleError(Exception ex)
{
    // error handling code here
}

HandleError(soEx);スタックがいっぱいになる直前に停止したため、実際には行にも例外がスローされます。

これが、スタックオーバーフロー例外をキャッチできないようにすることを選択した理由だと思います。これは、キャッチしてからそのcatchブロック内のメソッドを呼び出すことができないためです。

あなたの提案については、彼らはスタックサイズと有効なスタックサイズを持ちたくありませんでした. これらのことのいずれかがフレームワークを過度に複雑にし、部分的な解決策しか提供しません。

public void HandleError(Exception ex)
{
    try
    {
        HandleError(soEx);
    } Catch(StackOverflowException soEx)
    {
        HandleError(soEx);
    }
}

変数スタックがあり、実際に StackOverflowException がキャッチされるのを防ぐ方法がない場合、これは何か他のものをクラッシュさせます。

そのため、投げるだけでキャッチできないようにする方が簡単で、はるかに予測可能です。

編集:この回答は、CLR 2.0 以降で StackOverflowExceptions を引き続きキャッチできる唯一のケースを指摘しています。

于 2012-05-30T12:06:14.373 に答える