リリースコンパイルモードでのみ現れるが、デバッグモードでは発生しないバグおよびプログラムの異常な動作の一般的な理由は何ですか?
多くの場合、C++のデバッグモードでは、すべての変数はnullで初期化されますが、明示的に指定されない限り、リリースモードでは同じことは起こりません。
デバッグマクロと初期化されていない変数を確認します
プログラムがスレッドを使用している場合、最適化はリリースモードでいくつかの問題を引き起こす可能性があります。
また、リリースモードに直接関連していないなど、すべての例外を確認しますが、VC++のmemアクセス違反などの重要な例外を無視することもありますが、少なくともLinux、Solarisなどの他のOSでも同じことが問題になる可能性があります。理想的には、プログラムはNULLポインターへのアクセスなどの重要な例外をキャッチしないようにする必要があります。
一般的な落とし穴は、ASSERT内で副作用のある式を使用することです。
その他の違いは次のとおりです。
デバッグビルドでは問題ないが、リリースビルドではクラッシュする過去のバグに悩まされてきました。多くの根本的な原因(もちろん、このスレッドで既に要約されているものを含む)があり、私は次のすべてに気づきました。
#ifdef _DEBUG
のメンバー変数またはメンバー関数。これにより、デバッグビルドでクラスが異なるサイズになります。時々#ifndef NDEBUG
がリリースビルドで使用される#ifdef
があり、これはたまたま2つのビルドのいずれかにのみ存在します#pragma pack
のようなものがある場合、これは厄介な問題につながる可能性があります。プリコンパイル済みヘッダーと強制インクルードを使用しても同様の問題が発生する可能性がありますデバッグ/リリースバグの根底にたどり着くために長年にわたって蓄積してきたいくつかのヒント:
はい!条件付きコンパイルがある場合、タイミングのバグ(最適化されたリリースコードと最適化されていないデバッグコード)、メモリの再利用とデバッグヒープが存在する可能性があります。
特にC領域にいる場合は可能です。
1つの原因として、DEBUGバージョンがコードを追加して浮遊ポインターをチェックし、何らかの理由でコードがクラッシュしないように保護する(または正しく動作しない)可能性があります。この場合、コンパイラーから得られる警告やその他のメッセージを注意深く確認する必要があります。
別の原因は最適化である可能性があります(通常はリリースバージョンではオンで、デバッグではオフです)。コードとデータのレイアウトは最適化されている可能性があり、デバッグプログラムが未使用のメモリにアクセスしている間、リリースバージョンは予約済みのメモリにアクセスしようとしているだけでなく、コードを指しています!
編集:私は他の言及それを見ます:もちろん、デバッグモードでコンパイルしない場合、条件付きで除外されるコードセクション全体を持っているかもしれません。その場合、それは本当にコードをデバッグすることであり、プログラム自体の正確性に不可欠なものではないことを願っています!
CRTライブラリ関数は、デバッグとリリース(/ MDと/ MDd)で異なる動作をします。
たとえば、デバッグバージョンでは、主張を確認するために、指定された長さに渡すバッファーを事前に入力することがよくあります。例には、strcpy_s
、StringCchCopy
など。文字列がより早く終了する場合でも、szDestはnバイト長である方が良いでしょう。
確かに、たとえば、次のような構造を使用する場合
#if DEBUG
//some code
#endif
.NETでは、#if DEBUG
のような条件付きコンパイルを使用しなくても、コンパイラはデバッグモードよりもリリースモードでの最適化の方がずっと寛大です。
もっと多くの情報を提供する必要がありますが、はい、可能です。デバッグバージョンの機能によって異なります。リリースバージョンにコンパイルされないログまたは追加のチェックがあります。これらのデバッグ専用コードパスには、状態を変更したり、変な方法で変数に影響を与える意図しない副作用が生じる場合があります。デバッグビルドは通常、実行速度が遅いため、スレッド化に影響を及ぼし、競合状態を隠します。リリースコンパイルからの単純な最適化についても同じですが、リリースコンパイルが最適化として何かを短絡させる可能性があります(最近はほとんどありませんが)。
詳細なしで、「not OK」は、実行時にコンパイルしないか何らかのエラーをスローすることを意味すると想定します。 #if DEBUG
ステートメントを介して、またはConditional
属性でマークされたメソッドを介して、コンパイルバージョンに依存するコードがあるかどうかを確認します。
非void関数では、すべての実行パスはreturnステートメントで終了する必要があります。
デバッグモードでは、このようなパスをreturnステートメントで終了することを忘れた場合、関数は通常デフォルトで0を返します。
ただし、リリースモードでは、関数がガベージ値を返すことがあり、プログラムの実行方法に影響する場合があります。
有効なコードを壊す可能性がありますというコンパイラーの最適化があります。これは、それらが攻撃的すぎるためです。
最適化をあまり有効にせずにコードをコンパイルしてみてください。
デバッグコードとリリースコードが異なるように条件付きコンパイルがあり、リリースモードでのみ使用されるコードにバグがある場合、これは可能です。
それ以外は不可能です。デバッグコードとリリースコードのコンパイル方法に違いがあり、デバッガーで実行する場合としない場合のコードの実行方法に違いがありますが、それらの違いのいずれかがパフォーマンスの違い以外を引き起こす場合、問題はずっとそこにありました。
デバッグバージョンでは、エラーが発生していない可能性があります(タイミングまたはメモリの割り当てが異なるため)が、それはエラーがそこにないという意味ではありません。また、コードのタイミングを変更するデバッグモードに関連しない他の要因があり、エラーが発生するかどうかはわかりませんが、コードが正しい場合はエラーが発生しないという事実に帰着しますどんな状況でも。
そのため、エラーを発生させずに実行できるからといって、デバッグバージョンは問題ありません。リリースモードで実行したときにエラーが発生した場合、それはリリースモードではなく、エラーが最初からあったためです。
C/c ++でdllとpdbを作成していたときのことを覚えています。
私はこれを覚えている:
そして、最高を願っていました。
これらのバグに取り組んでいる間、実稼働を遅らせないために、時々dllのデバッグバージョンをクライアントに一時的に配信しました。
レジスタの以前の値を復元しなかったアセンブリ関数を呼び出していたときに、それを経験しました。
「リリース」構成では、VSは/ O2を使用してコンパイルし、コードの速度を最適化しました。したがって、CPUレジスタへのマッピング(最適化のため)だけである一部のローカル変数は、前述の関数と共有され、深刻なメモリ破損につながりました。
とにかく、コードのどこかでCPUレジスタを間接的に混乱させていないかどうかを確認してください。
それが可能だ。それが発生し、条件付きコンパイルが含まれていない場合、プログラムが間違っていることを確信でき、偶然のメモリ初期化またはメモリ内のレイアウトのためだけにデバッグモードで動作しています!
別の理由としては、DB呼び出しが考えられます。同じスレッドで同じレコードを複数回保存および更新していますか?前のcreateコマンドがまだ処理中で、更新のためにdb呼び出しがレコードを見つけることができなかったため、更新が失敗したか、期待どおりに機能しなかった可能性があります。デバッガーが着陸前にすべての保留中のタスクを完了することを確認するため、これはデバッグでは発生しません。