StackOverflowException
私が知る限り、キャッチ不能であるべき根本的な理由はありません。それでもそうです。
スレッドのスタックには最大サイズがあり、ビット数に応じてデフォルトで 1MB または 4MB になりますが、このスペースは予約されているだけです。何かが実際に多くのスタックを必要とするまで、コミットされません (したがって、仮想アドレス空間のみを使用します)。
私の知る限り、キャッチできない理由の背後にある基本的な考え方は、それまでにすべてのスタックを使い果たしたため、スタック外の状態用に非常に注意深く設計されたコード以外は実際には何も実行できないということです。しかし、これには明らかな解決策が必要です。すべてのスタック スペースがなくなるStackOverflowException
前にスローするのです。
なぜこれが行われないのですか?私が考えることができる唯一のリモートで賢明な理由は、これが消費する余分な仮想アドレス空間(実際のメモリ使用量ではありません!) が、この例外をキャッチ可能にするメリットに値しないと判断されたことです。
私が考慮していない他の懸念事項はありますか?
SOでこれに対処するほとんどの回答は、これを適切に機能させることは不可能であることを暗示しているように思われるため、質問する必要があると感じています.NETがそれらをキャッチできない理由です。
キャッチ可能なバリアントの正確な実装の詳細は重要ではないように見えますが、ここに 1 つのアイデアを示します。まず、デフォルトの予約済みスタック サイズを 2 倍にしますが、1MB の使用量でトリガーするように例外を設定します。ここまでは、既存のアプローチとまったく同じです。ただし、しきい値に達したら、キャッチできない例外をスローする代わりに、しきい値を 1.5MB に増やしながら、キャッチ可能な例外をスローします。例外がキャッチされ、再度制限を超えた場合は、1.75MB に設定します。次に1.875MB。ネストされ処理された各例外は、キャッチできないバリアントをスローする必要があるほど 2MB に近づくまで、処理される余分なスタック スペースの量が減少し続けます。
StackOverflowException の処理が成功した後にしきい値を元に戻すには、書き込み時に失敗するために吹き飛ばしたスタック サイズの半分 (最初のインスタンスでは 0.5MB) でメモリ ページをマークしましょう。障害ハンドラーは、スタック使用量がそのレベルに戻ったときにほぼ排他的にトリガーされるため、コストはかかりません。ハンドラーは実際のスタック サイズをチェックし、適切な場合はしきい値を元に戻します。