2009-07-10 3 views
0

私はネストされたtry/catchステートメントについて考えていて、もしあれば、JITがコンパイル済みILの最適化または簡略化を実行できる条件について考え始めました。.NET JITはネストされたtry/catchステートメントを最適化しますか?

説明するために、以下の機能的に同等の例外ハンドラの表現を考えてみましょう。ネストされたtry文のスタックフレーム内には、追加の変数の参照や関数呼び出しが存在しないと仮定すると、

// Nested try/catch 
try 
{ 
    try 
    { 
    try 
    { 
     foo(); 
    } 
    catch(ExceptionTypeA) { } 
    } 
    catch(ExceptionTypeB) { } 
} 
catch(ExceptionTypeC) { } 

// Linear try/catch 
try 
{ 
    foo(); 
} 
catch(ExceptionTypeA) { } 
catch(ExceptionTypeB) { } 
catch(ExceptionTypeC) { } 

、JITは、スタックフレームは、線形例に崩壊することができると結論することができますか?

ここで、次の例はどうですか?

void Try<TException>(Action action) 
{ 
    try 
    { 
    action(); 
    } 
    catch (TException) { } 
} 

void Main() 
{ 
    Try<ExceptionC>(Try<ExceptionB>(Try<ExceptionA>(foo))); 
} 

私は、デリゲートの呼び出しをインライン化するJITのためのどのような方法があるとは思わないので、この例では、前の1に削減することができません。しかし、foo()ExceptionCとなった場合、このソリューションは線形の例に比べてパフォーマンスが低下しますか?フレームに含まれる余分なデータは最小限であるにもかかわらず、デリゲートの呼び出しからスタックフレームを分解するために追加のコストがかかると思われます。

+1

最初の2つのケースでILを調べましたか? – womp

答えて

8

最初のケースでは、となります。キャッチブロック内で何もしていないときはと機能的に同等です。

この場合、今
try 
{ 
    try 
    { 
     foo(); 
    } 
    catch (IOException) 
    { 
     throw new ArgumentException(); // Caught by other handler 
    } 
} 
catch (ArgumentException) 
{ 
    Console.WriteLine("Caught"); 
} 

try 
{ 
    foo(); 
} 
catch (IOException) 
{ 
    throw new ArgumentException(); // Bubbles up to caller 
} 
catch (ArgumentException) 
{ 
    Console.WriteLine("Caught"); 
} 

違いは明白ですが、catchブロックは、JITがスローされる可能性があるかを知ることを意図しているか、いくつかの任意のメソッドを呼び出した場合:それ以外の場合は、これを考慮?最高の慎重さ。

これは、JITが空のキャッチブロックの最適化を実行するという選択肢を残しています。これは最初は強く推奨されていません。私は、JITが悪いコードを検出してそれを少し速く走らせるために時間を費やすことを望んでいません - 実際には最初の場所にパフォーマンスの違いがある場合です。

+0

分析Jonありがとうございます。私の考えでは、空のキャッチハンドラーはノースロー操作を実行していました。ただし、OutOfMemoryExceptionやThreadAbortExcetpionなどの例外がfoo()の外部の理由で発生する可能性があるため、分析は引き続き適用されます。 –

4

パフォーマンスに関してtry/catch/finally領域を理解することは、そのような領域がコードの通常の実行に対してトランスペアレントであることです。つまり、あなたのコードがキャッチする例外をスローしない場合、try/catch/finally領域にはZEROがコード実行パフォーマンスに影響を与えます。

ただし、例外が発生すると、ランタイムは、発生したサイトからスタックを歩き始め、メタデータのテーブルをチェックして問題のサイトがいずれかのクリティカルなtryブロックに含まれているかどうかを確認します。見つかった場合(適切なcatchブロックまたはfinallyブロックがある場合)、関連するハンドラが識別され、実行がこのポイントに分岐します。

例外を発生させて処理するプロセスは、パフォーマンスの観点からは高価です。プログラマは、例外的な状況以外の状況でプログラムフローを通知または制御する方法として例外を使用すべきではありません。

+0

+1 try-catchブロックのランタイムコストを説明します –

関連する問題