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


280

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

私の知る限り、手動で変更しない場合のこれらの構成の唯一の違いは、DebugDEBUG定数が定義されており、Release最適化コードがチェックされていることです。

だから私の質問は実際には2つあります:

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

  2. デバッグ構成で正常に実行され、リリース構成で失敗する可能性のあるコードの種類はありますか?または、テストされ、デバッグ構成で正常に機能するコードがリリース構成でも正常に機能することを確認できますか?


回答:


511

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ジッタでは大きな問題です。適切なものを選択することが、パフォーマンスにとって重要です。

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

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

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


23
すべてのコレクションが配列を使用しているとは思いません。配列LinkedList<T>はあまり使用されていませんが、使用していません。
11年

CLRはFPUを53ビット精度(64ビット幅のdoubleに一致)に構成するので、Float64値の80ビット拡張double計算はありません。ただし、Float32の計算はこの53ビットの精度で計算され、メモリに格納された場合にのみ切り捨てられる場合があります。
Govert

2
このvolatileキーワードは、スタックフレームに格納されているローカル変数には適用されません。msdn.microsoft.com/en-us/library/x13ttww7.aspxのドキュメントから:「volatileキーワードは、クラスまたは構造体のフィールドにのみ適用できます。ローカル変数はvolatileと宣言できません。」
Kris Vandermotten、2014

8
控えめな修正として、この点でDebugReleaseビルドの違いが実際にあるのは、通常はオンになっているReleaseがオフになっている「コードを最適化する」チェックボックスだと思いますDebug。これは、Visual Studioのプロジェクトプロパティページにあるものを超える2つのビルド構成の間に「魔法の」目に見えない違いがあると読者が考え始めないようにするためです。
チッコドロ2014

3
おそらく、System.Diagnostics.Debugのメソッドは、デバッグビルドでは何も実行しないことに言及する価値があります。また、変数はすぐには確定されません(stackoverflow.com/a/7165380/20553)。
Martin Brown、

23
  1. はい、多くのパフォーマンスの違いがあり、これらは実際にコード全体に当てはまります。デバッグはほとんどパフォーマンスの最適化を行わず、リリースモードは非常に多くなります。

  2. DEBUG定数に依存するコードのみが、リリースビルドで異なる動作をする場合があります。それ以外に、問題はありません。

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


2
これはすべて正しいですが、違いを測定できますか?または、プログラムの使用中に違いに気づきましたか?もちろん、デバッグモードでソフトウェアをリリースすることをだれにも勧めたくありませんが、問題はパフォーマンスに大きな違いがあるかどうかで、それがわかりません。
testalino

2
デバッグバージョンは、リリースバージョンよりも元のソースコードと非常に高い相関があることにも注意してください。実行可能ファイルをリバースエンジニアリングしようとする人がいるかもしれないと考えている場合でも、デバッグバージョンを導入することで実行可能ファイルを簡単に作成したくないでしょう。
jwheron、

2
@testalino-まあ、最近は難しいです。プロセッサーは、ユーザーのアクションのためにユーザーがプロセスが実際にコードを実行するのをほとんど待たないほど速くなっているため、これはすべて相対的なものです。ただし、実際に時間のかかるプロセスを実行している場合は、気づくでしょう。たとえば、次のコードは、40%遅く実行されDEBUGますAppDomain.CurrentDomain.GetAssemblies().Sum(p => p.GetTypes().Sum(p1 => p1.GetProperties().Length))
Pieter van Ginkel、

2
また、asp.netリリースしていてデバッグの代わりにデバッグを使用している場合、ページにいくつかのスクリプトが追加されることがあります。たとえば、MicrosoftAjax.debug.js約7k行あります。
BrunoLM 2010年

13

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

ただし、多くの計算を必要とする計算がある場合は、違いに気付くでしょう(計算の性質に依存しますが、@ Pieterが言及したように、40%になる可能性があります)。

これは基本的にデザインのトレードオフです。DEBUGビルドでリリースする場合、ユーザーに問題が発生すると、より意味のあるトレースバックを取得でき、より柔軟な診断を行うことができます。DEBUGビルドでリリースすることにより、オプティマイザが不明瞭なハイゼンバグを生成することも回避できます。


11
  • 私の経験では、Releaseビルドでは、中規模以上のアプリケーションの応答性が著しく向上しています。アプリケーションで試してみて、感じを見てください。

  • リリースビルドを使用すると、デバッグビルドコードが競合状態やその他のスレッド関連のバグを抑制できる場合があります。最適化されたコードは、命令の再配列をもたらす可能性があり、より高速な実行は特定の競合状態を悪化させる可能性があります。


9

.NET Debugビルドを本番環境にリリースしないでください。エディット・アンド・コンティニューをサポートするか、他に何を知っているかを示す醜いコードが含まれている場合があります。私の知る限り、これはC#ではなくVBでのみ発生します(注:元の投稿にはC#のタグが付けられています)。実際、.NET 4.0より前のバージョンでは、VBコードは、エディットアンドコンティニューをサポートするために構築したイベントを持つオブジェクトのインスタンスの数に比例してメモリリークを起こします。(これはhttps://connect.microsoft.com/VisualStudio/feedback/details/481671/vb-classes-with-events-are-not-garbage-collected-when-debuggingに従って修正されると報告されていますが、生成されたコード厄介に見え、WeakReferenceオブジェクトを作成して静的リストに追加している間ロックを保持する)私は確かに本番環境でこの種のデバッグサポートを必要としません!


デバッグビルドを何度もリリースしましたが、問題は見られません。おそらく唯一の違いは、サーバー側のアプリケーションが多くのユーザーをサポートするWebアプリではないことです。ただし、処理負荷が非常に高いサーバー側アプリケーションです。私の経験から、デバッグとリリースの違いは完全に理論的なもののようです。私は私たちのアプリのどれとも実際的な違いを見たことがありません。
Sam Goldberg

5

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

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


フォローアップするために、リリースバグの例を示す記事を次に示します。codeproject.com
Roly

アプリケーションがデバッグ設定でテストおよび承認されている場合、エラーが抑制されていても、展開中にリリースビルドが失敗する場合は、やはり問題です。
ØyvindBråthen

4

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


1
IOにバインドされたコードの場合、リリースビルドはそのデバッグよりも速くありません。
Richard

0
    **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:
   1) More optimized code
   2) Some additional instructions are removed and developer cant set a breakpoint on every source code line.
   3) Less memory is used by the source code at runtime.
   4) Scripts & images downloaded by webresource.axd are cached.
   5) It has small size, and runs fast.

2
リリースモードよりも、リストの最初の要素が正しく番号付けされない場合があります。また、リスト内の一部の要素が重複しています。:)
Gian Paolo
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.