.NETのJITの最適化は、try / catch文を入れ子にしていますか?
-
12-09-2019 - |
質問
私は、ネストされたのtry / catch文を考えると下の条件について考え始めてきた、もしあれば、JITコンパイルされたILの最適化や簡素化を行うことができます。
説明するために、例外ハンドラの以下の機能的に等価な表現を考える。
// Nested try/catch
try
{
try
{
try
{
foo();
}
catch(ExceptionTypeA) { }
}
catch(ExceptionTypeB) { }
}
catch(ExceptionTypeC) { }
// Linear try/catch
try
{
foo();
}
catch(ExceptionTypeA) { }
catch(ExceptionTypeB) { }
catch(ExceptionTypeC) { }
ネストされたtry文のスタックフレーム内には、追加の変数の参照や関数呼び出しが存在しないと仮定すると、JITは、スタックフレームは、線形例に崩壊することができると結論づけることができますか?
今どのように次の例についてはどうですか?
void Try<TException>(Action action)
{
try
{
action();
}
catch (TException) { }
}
void Main()
{
Try<ExceptionC>(Try<ExceptionB>(Try<ExceptionA>(foo)));
}
私は、JITは、デリゲートの呼び出しをインライン化するためにどのような方法があるとは思わないので、この例では、前の1に削減することができません。線形例と比較すると、しかしfoo()
投げExceptionC
のイベントでは、このソリューションは、貧しい実行していますか?私は、フレームに含まれる余分なデータが最小であるにも関わらず、デリゲートの呼び出しからスタックフレームを取り壊すために余分なコストがある疑います。
解決
これは最初のケースで、彼らはののみの機能的に同等のあなたはcatchブロック内何もしないているときだということは注目に値します。それ以外の場合は、これを考慮します:
try
{
foo();
}
catch (IOException)
{
throw new ArgumentException(); // Bubbles up to caller
}
catch (ArgumentException)
{
Console.WriteLine("Caught");
}
対
try
{
try
{
foo();
}
catch (IOException)
{
throw new ArgumentException(); // Caught by other handler
}
}
catch (ArgumentException)
{
Console.WriteLine("Caught");
}
さて、この場合に違いは明白ですが、catchブロックは、いくつかの任意のメソッドを呼び出す場合、JITが知っていることを意図しているか何を投げられるのでしょうか?慎重にするのが最良ます。
強く最初の場所で推奨されて練習 -これは、空のcatchブロックのための最適化を実行するJITのオプションを私たちに残します。私は、JITが不正なコードを検出して、それはより速く、非常にわずかに実行しようとして時間を費やす必要はありません - 実際に最初の場所で任意のパフォーマンスの違いがあります場合は、
。他のヒント
パフォーマンスに関してのtry / catch /最後に地域の私の理解では、このような領域は、コードの定期的な実行に透過的であるということです。あなたのコードは、キャッチする例外をスローしない場合、すなわち、、その後のtry / catch /最後に領域がのZEROコード実行のパフォーマンス上ののインパクトを持っています。
ただし、例外が発生したときに、ランタイムは、それが問題のサイトが重要なのtryブロックのいずれかに含まれているかどうかを確認するために、メタデータのテーブルをチェックし、提起されたサイトからのスタックを歩い開始します。 1が検出された(そしてそれが対象とcatchブロックまたはfinallyブロックを持っている)場合は、関連するハンドラは、このポイントに特定され、分岐している。
上げ、例外を処理するプロセスは、パフォーマンスの観点から高価です。プログラマは、シグナルまたは例外的な状況以外でのプログラムの流れを制御する方法として、例外を使うべきではない(意図しゃれ。)