web-dev-qa-db-ja.com

デバッグビルドとリリースビルドのパフォーマンスの違い

私は通常、プログラムのDebugRelease構成の切り替えを気にしていないことを認めなければなりません、そして私は通常プログラムが実際に顧客の場所に展開されている場合でも、Debug構成を選択しました。

私が知る限り、手動で変更しない場合のこれらの構成の唯一の違いは、DebugDEBUG定数が定義されていること、およびReleaseOptimize codeをチェックします。

したがって、私の質問は実際には2つあります。

  1. これら2つの構成の間にパフォーマンスの違いはありますか?ここでパフォーマンスに大きな違いを引き起こす特定のタイプのコードはありますか、それとも実際にはそれほど重要ではありませんか?

  2. Debug構成で正常に実行されるコードのタイプはありますか?Release構成で失敗する可能性がありますか? Debug構成でテストされ、正常に動作するコードは、リリース構成でも正常に動作します。

273

C#コンパイラ自体は、リリースビルドで放出されたILを大幅に変更しません。注目すべきは、中括弧にブレークポイントを設定できるNOPオペコードを発行しないことです。大きなものは、JITコンパイラーに組み込まれているオプティマイザーです。私はそれが次の最適化を行うことを知っています:

  • メソッドのインライン化。メソッド呼び出しは、メソッドのコードを注入することで置き換えられます。これは大きなもので、プロパティアクセサを本質的に無料にします。

  • CPUレジスタ割り当て。ローカル変数とメソッドの引数は、スタックフレームに格納されることなく(またはそれほど頻繁に)CPUレジスタに格納されたままになりません。これは大きなもので、最適化されたコードのデバッグを非常に困難にする点で注目に値します。 volatileキーワードに意味を与える。

  • 配列インデックスのチェック除去。配列を操作するときの重要な最適化(すべての.NETコレクションクラスは内部的に配列を使用します)。 JITコンパイラーは、ループが範囲外の配列のインデックスを作成しないことを確認できる場合、インデックスチェックを削除します。大きなもの。

  • ループの展開。ボディ内でコードを最大4回繰り返し、ループを少なくすることにより、小さなボディを持つループが改善されます。ブランチコストを削減し、プロセッサのスーパースカラー実行オプションを改善します。

  • デッドコードの除去。 if(false){/.../}のようなステートメントは完全に削除されます。これは、一定の折りたたみとインライン化が原因で発生する可能性があります。他の場合は、JITコンパイラーがコードに副作用がないと判断できる場合です。この最適化により、コードのプロファイリングが非常に難しくなります。

  • コードの巻き上げ。ループの影響を受けないループ内のコードは、ループの外に移動できます。 Cコンパイラーのオプティマイザーは、ホイストの機会を見つけるのにより多くの時間を費やします。ただし、必要なデータフロー分析のために費用のかかる最適化であり、ジッターは時間を費やすことができないため、明らかなケースのみを巻き上げます。 .NETプログラマーに、より良いソースコードを記述し、自分自身を巻き上げることを強制します。

  • 共通の部分式の除去。 x = y + 4; z = y + 4; z = xになります。 dest [ix + 1] = src [ix + 1];のようなステートメントではかなり一般的です。ヘルパー変数を導入せずに読みやすくするために書かれています。可読性を損なう必要はありません。

  • 一定の折りたたみ。 x = 1 + 2; x = 3になります。この単純な例はコンパイラーによって早期にキャッチされますが、他の最適化がこれを可能にするJIT時に発生します。

  • コピー伝播。 x = a; y = x; y = aになります。これにより、レジスタアロケータがより適切な判断を下すことができます。動作するレジスタがほとんどないため、x86ジッタでは大きな問題になります。適切なものを選択することは、パフォーマンスにとって重要です。

これらは非常に重要な最適化であり、たとえば、アプリのデバッグビルドのプロファイルを作成してリリースビルドと比較するときにgreatの違いを生む可能性があります。ただし、コードがクリティカルパスにある場合、コードの5〜10%が実際であることがプログラムのパフォーマンスに影響します。 JITオプティマイザーは、何が重要であるかを前もって知るほどスマートではなく、すべてのコードに「11に回す」ダイヤルのみを適用できます。

プログラムの実行時間に対するこれらの最適化の効果的な結果は、多くの場合、他の場所で実行されるコードの影響を受けます。ファイルの読み取り、dbaseクエリの実行など。JITオプティマイザーが行う作業を完全に非表示にします。それは気にしない:)

JITオプティマイザーは、非常に信頼性の高いコードです。これは、主に何百万回もテストされているためです。プログラムのリリースビルドバージョンで問題が発生することは非常にまれです。しかし、それは起こります。 x64とx86の両方のジッターには、構造体に問題があります。 x86ジッターは浮動小数点の一貫性に問題があり、浮動小数点計算の中間体がメモリにフラッシュされたときに切り捨てられるのではなく、80ビット精度でFPUレジスタに保持されると微妙に異なる結果を生成します。

504
Hans Passant
  1. はい、多くのパフォーマンスの違いがあり、これらは実際にコード全体に適用されます。デバッグはパフォーマンスの最適化をほとんど行わず、モードを非常に解放します。

  2. DEBUG定数に依存するコードのみが、リリースビルドで異なる動作をする可能性があります。それに加えて、問題は発生しないはずです。

DEBUG定数に依存するフレームワークコードの例は、Debug.Assert()メソッドで、属性[Conditional("DEBUG)"]が定義されています。これは、DEBUG定数にも依存することを意味し、これはリリースビルドには含まれていません。

23

これは、アプリケーションの性質に大きく依存します。アプリケーションがUIに負荷がかかる場合、最新のコンピューターに接続されている最も遅いコンポーネントがユーザーであるため、おそらく違いに気付かないでしょう。いくつかのUIアニメーションを使用する場合、DEBUGビルドで実行しているときに顕著なラグを知覚できるかどうかをテストすることができます。

ただし、計算量の多い計算が多​​数ある場合は、違いに気づきます(計算の性質によって異なりますが、@ Pieterが述べたように40%に達する可能性があります)。

基本的には設計上のトレードオフです。 DEBUGビルドでリリースする場合、ユーザーが問題を経験すると、より意味のあるトレースバックを取得でき、はるかに柔軟な診断を行うことができます。 DEBUGビルドでリリースすることにより、オプティマイザがあいまいな Heisenbugs を生成することも回避できます。

12
Lie Ryan
  • 私の経験では、中規模または大規模のアプリケーションは、リリースビルドで顕著に反応します。アプリケーションで試してみて、どのように感じられるかを確認してください。

  • リリースビルドで噛みつくことのできることの1つは、デバッグビルドコードが競合状態やその他のスレッド関連のバグを抑制することがあるということです。最適化されたコードは命令の並べ替えをもたらし、実行の高速化は特定の競合状態を悪化させる可能性があります。

11
Dan Bryant

。NETデバッグビルドを実稼働環境にリリースしないでください。 Edit-and-Continueをサポートするためのorいコードや、他に何を知っているかが含まれている場合があります。私が知る限り、これはVBではなくC#でのみ発生します(注:元の投稿にはC#のタグが付けられます)。マイクロソフトがデバッグビルドで許可されていると考えていることについて。実際、.NET 4.0より前のVBコードは、Edit-and-Continueをサポートするために構築するイベントを持つオブジェクトのインスタンスの数に比例してメモリをリークします。 (これは https://connect.Microsoft.com/VisualStudio/feedback/details/481671/vb-classes-with-events-are-not-garbage-collected-when-debuggingごとに修正されると報告されていますが、 、生成されたコードは厄介に見え、WeakReferenceオブジェクトを作成し、ロックを保持しながら静的リストに追加します)実稼働環境での一種のデバッグサポート!

9
Jason Kresowaty

私の経験では、リリースモードから出た最悪の事態は、あいまいな「リリースバグ」です。 IL(中間言語)はリリースモードで最適化されているため、デバッグモードでは現れなかったバグの可能性があります。この問題をカバーする他のSO質問があります: リリースバージョンのバグがデバッグモードに存在しない一般的な理由

これは、デバッグモードでは単純なコンソールアプリが完全に正常に実行されるが、まったく同じ入力が与えられるとリリースモードではエラーになる1回または2回発生しました。これらのバグのデバッグは非常に困難です(皮肉なことにリリースモードの定義による)。

5
Roly

1)実装に大きく依存していると思います。通常、違いはそれほど大きくありません。私は多くの測定を行いましたが、多くの場合、違いが見られませんでした。アンマネージコード、多くの巨大な配列などを使用すると、パフォーマンスの違いはわずかに大きくなりますが、異なる世界(C++など)ではありません。 2)通常、リリースコードでは、表示されるエラーが少なく(許容誤差が高い)、スイッチは正常に機能するはずです。

3
testalino
    **Debug Mode:**
    Developer use debug mode for debugging the web application on live/local server. Debug mode allow developers to break the execution of program using interrupt 3 and step through the code. Debug mode has below features:
   1) Less optimized code
   2) Some additional instructions are added to enable the developer to set a breakpoint on every source code line.
   3) More memory is used by the source code at runtime.
   4) Scripts & images downloaded by webresource.axd are not cached.
   5) It has big size, and runs slower.

    **Release Mode:**
    Developer use release mode for final deployment of source code on live server. Release mode dlls contain optimized code and it is for customers. Release mode has below features:
    More optimized code
    Some additional instructions are removed and developer can’t set a breakpoint on every source code line.
   1) Less memory is used by the source code at runtime.
   2) Scripts & images downloaded by webresource.axd are cached.
   3) It has small size, and runs fast.
   4) Scripts & images downloaded by webresource.axd are cached.
   5) It has small size, and runs fast.
0
Nandha kumar