13

.NETでいくつかのStackOverflowExceptionsをヒットした後、.NETが提供する未処理の例外ハンドラー(Application.ThreadException / AppDomain.UnhandledException)を完全にバイパスしていることに気付きました。これらの例外ハンドラーに重要なクリーンアップコードがあるため、これは非常に厄介です。

これを克服する方法はありますか?

4

4 に答える 4

25

いわゆる「非同期例外」には 3 種類あります。それは、ThreadAbortException、OutOfMemoryException、および上記の StackOverflowException です。これらの例外は、コード内の任意の命令で発生することが許可されています。

そして、それらを克服する方法もあります:

最も簡単なのは ThreadAbortException です。現在のコードが最終ブロックで実行されるとき。ThreadAbortExceptions は、finally ブロックの最後に「移動」されたようなものです。したがって、finally ブロック内のすべてを ThreadAbortException で中止することはできません。

OutOfMemoryException を回避するには、ヒープに何も割り当てないという 1 つの方法しかありません。これは、新しい参照型を作成することは許可されていないことを意味します。

StackOverflowException を克服するには、フレームワークの助けが必要です。このヘルプは、制約付き実行領域に現れます。必要なスタックは、実際のコードが実行される前に割り当てられ、さらに、コードが既に JIT コンパイルされているため、実行可能であることも保証されます。

制約付き実行領域でコードを実行するための 3 つの形式があります ( BCL チーム ブログからコピー)。

  • ExecuteCodeWithGuaranteedCleanup、try/finally のスタック オーバーフロー セーフ形式。
  • RuntimeHelpers.PrepareConstrainedRegions への呼び出しの直後の try/finally ブロック。try ブロックは制約されませんが、その try のすべての catch ブロック、finally ブロック、および fault ブロックは制約されます。
  • クリティカル ファイナライザーとして - CriticalFinalizerObject のサブクラスには、オブジェクトのインスタンスが割り当てられる前に熱心に準備されるファイナライザーがあります。
    • 特別なケースは SafeHandle の ReleaseHandle メソッドです。これは、サブクラスが割り当てられる前に熱心に準備され、SafeHandle の重要なファイナライザーから呼び出される仮想メソッドです。

詳細については、次のブログ投稿を参照してください。

Constrained Execution Regions とその他の正誤表 [Brian Grunkemeyer] (BCL チーム ブログ)。

アトミシティと非同期例外の失敗に関する Joe Duffy の Weblog では、非同期例外と .net Framework の堅牢性に関する非常に優れた概要を説明しています。

于 2008-09-20T12:33:05.673 に答える
18

あまり; スタックオーバーフロー、またはCLR自体の中でメモリ不足の例外が発生した場合は、何かが重大な問題を抱えていることを意味します(私は通常、ばかげていて再帰プロパティを作成したときに発生します)。

この状態が発生すると、CLRが新しい関数呼び出しまたはメモリを割り当てて、例外ハンドラーを呼び出せるようにする方法がありません。これは「今すぐ停止する必要がある」シナリオです。

ただし、自分で例外をスローすると、例外ハンドラが呼び出されます。

于 2008-09-20T09:37:58.590 に答える
1

スタックオーバーフローは、例外ハンドラーを呼び出すためにさらにスタックメモリを割り当てることができないため、回復できるものではありません。

実際にできることは、原因を突き止めて、それがまったく起こらないようにすることだけです(たとえば、再帰に注意し、スタックに大きなオブジェクトを割り当てないでください)。

于 2008-09-20T09:41:02.407 に答える
1

上記のblowdartはそれを釘付けにしました。彼が好んで呼んでいるように、ばかげた再帰プロパティ。コードの入力が速すぎるのは本当に問題です。

private Thing _myThing = null;

Public Thing MyThing
{
   get{
        return this.MyThing;}
   set{
        this.MyThing = value;}
}
于 2010-06-01T19:07:41.150 に答える