[解決済み】デバッグビルドとリリースビルドの性能差について
質問
私は、普段から、わざわざ デバッグ と リリース のコンフィギュレーションを使用しています。 デバッグ という構成で、実際にお客様のところにデプロイされる場合もあります。
私の知る限り、手動で変更しない場合、これらの設定の唯一の違いは
デバッグ
があります。
DEBUG
定数が定義されており
リリース
は
コードの最適化
をチェックした。
そこで、質問は2つあります。
-
この2つの構成で、パフォーマンスに大きな違いはありますか?ここでパフォーマンスに大きな違いをもたらす特定のタイプのコードがあるのでしょうか、それとも実際はそれほど重要ではないのでしょうか?
-
の下で問題なく実行できるコードのタイプはありますか? デバッグ の下では失敗する可能性があります。 リリース の下でテストされ、問題なく動作しているコードを、本当に デバッグ の設定は、Releaseの設定でも問題なく動作します。
解決方法は?
C#コンパイラー自体は、リリースビルドでは、出力されるILに大きな変更はありません。 注目すべきは、中括弧にブレークポイントを設定するための NOP オペコードが出力されなくなったことです。 大きいのは、JITコンパイラに組み込まれているオプティマイザです。 以下のような最適化が行われることが分かっています。
-
メソッドのインライン化。 メソッド呼び出しは、メソッドのコードを注入することで置き換えられる。 これは大きなもので、プロパティアクセサを本質的に自由にするものです。
-
CPUレジスタの割り当て。 ローカル変数とメソッドの引数は、スタックフレームに戻されることなく(または頻度が少なくても)CPUレジスタに格納されたままにすることができます。 これは大きな問題で、最適化されたコードのデバッグを非常に難しくしていることで注目されています。 また ボラティリティ キーワードに意味を持たせています。
-
配列のインデックスチェックの省略。 配列(すべての.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のジッターでは、扱うレジスタが少ないので、これは大きな問題です。 正しいレジスタを選択させることは、性能にとって非常に重要です。
これらは非常に重要な最適化であり、これにより 偉大な 例えば、アプリのデバッグビルドをプロファイリングして、リリースビルドと比較したときに、大きな違いが生まれます。 ただし、これはクリティカルパス上にあるコードに限った話です。 実際に プログラムの性能に影響を与えます。 JITオプティマイザは、何が重要かを前もって知るほど賢くないので、すべてのコードに「quot; turn it to eleven"」ダイヤルを適用するしかないのです。
これらの最適化がプログラムの実行時間に及ぼす効果的な結果は、しばしば他の場所で実行されるコードに影響されます。 ファイルの読み込み、データベースクエリの実行など。 JITオプティマイザが行う作業は、完全に見えなくなってしまうのです。 しかし、JITオプティマイザはそれを気にしません:)
JITオプティマイザはかなり信頼性の高いコードで、そのほとんどは何百万回もテストされているからです。 リリースビルド版で問題が発生することは極めて稀です。 しかし、実際に起こることもあります。 x64とx86の両方のジッターで、構造体に関する問題が発生しました。 x86 ジッターは浮動小数点数の整合性に問題があり、浮動小数点数計算の中間値を FPU レジスタに 80 ビット精度で保持すると、メモリにフラッシュする際に切り捨てられる代わりに、微妙に異なる結果を生成してしまうのです。
関連
-
[解決済み] C#のStringとstringの違いは何ですか?
-
[解決済み] callとapplyの違いは何ですか?
-
[解決済み] SQLiteのINSERT/per-secondのパフォーマンスを向上させる
-
[解決済み] Python 3で「1000000000000000 in range(1000000000000001)」はなぜ速いのですか?
-
[解決済み] 要素ごとの加算は、結合ループよりも分離ループの方がはるかに高速なのはなぜですか?
-
[解決済み] .NETでのdecimal, float, doubleの違い?
-
[解決済み] C#がforeachで変数を再利用するのは理由があるのか?
-
[解決済み] なぜList<T>を継承しないのですか?
-
[解決済み] WPFの場合、x:Name属性とName属性の違いは何ですか?
-
[解決済み] Intel CPU の _mm_popcnt_u64 で、32 ビットのループカウンターを 64 ビットに置き換えると、パフォーマンスが著しく低下します。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】プログラム実行中に1秒待つ
-
[解決済み】「namespace x already contains a definition for x」エラーの修正方法は?VS2010にコンバートした後に発生しました。
-
[解決済み】Entity FrameworkからのSqlException - セッション内で他のスレッドが動作しているため、新しいトランザクションは許可されません。
-
[解決済み】Linq 構文 - 複数列の選択
-
[解決済み】2つ(またはそれ以上)のリストを1つに統合する(C# .NETで
-
[解決済み】aspNetCore 2.2.0 - AspNetCoreModuleV2 エラー
-
[解決済み] 関数を終了するには?
-
[解決済み】「namespace」なのに「type」のように使われる。
-
[解決済み] .NETのガベージコレクションを理解する
-
[解決済み] デバッグとリリースの性能比較