デバッガーを学ぶ
テキストベース、完全なIDE、またはそれらのいくつかのブレンドであるかどうかにかかわらず、デバッガーを理解することは本当に役立ちます。詳細はあまり説明しないので、一般的なケースについて説明します。
1)ブレークポイント
コードの行で停止するだけでなく、多くのデバッガーでは、コードを何度か通過した後、または一部のメモリが値を変更したときに、条件が発生したとき(「x> 5」など)にブレークするように指定できます。これは、コードがどのように悪い状態になるかを理解するのに非常に役立ちます。たとえば、ポインターが逆参照されたときにクラッシュをキャッチするのではなく、ポインターがnullになるのを監視します。
2)コードのステップ実行
関数にステップインし、コードに沿って行ごとに、行をジャンプして(「次のステートメントを設定」)、関数から「上に」移動できます。これは、コードの実行を追跡して、思ったとおりに動作することを確認する非常に強力な方法です:-)
3)式の評価
したがって、変数をウォッチリスト/ウィンドウに配置して、ブレークポイントに到達したときやコードをステップ実行したときに値の変化を確認できますが、通常は複雑な式の評価も行うことができます。たとえば、「x + y / 5」が評価されます。一部のデバッガーでは、関数呼び出しを監視リストに入れることもできます。「time()」、「MyFunction(...)」、「time()」などを実行して、関数にかかった時間のクロックタイミングを取得できます。
4)例外とシグナル処理
したがって、言語が例外やシグナルをサポートしている場合は、通常、これに対応する方法についてデバッガを構成できます。一部のデバッガーでは、例外のキャッチに失敗した後ではなく、例外が発生しようとしている時点でコードに侵入できます。これは、プログラムが別のユーザーアカウントで実行されているため、「ファイルが見つかりません」エラーなどの奇妙な問題を追跡するのに役立ちます。
5)プロセス/コアへのアタッチ
そのため、時々、デバッガーを使用して、問題のある既存のプロセスにジャンプする必要があります。近くにソースコードがあり、デバッグシンボルが損なわれていない場合は、最初からデバッガーで開始したかのように飛び込むことができます。これはコアダンプの場合も同様ですが、通常はそれらのデバッグを続行できません(プロセスはすでに終了しています)。
ビルド構成
デバッグシンボル、最適化、その他のコンパイラフラグなどの機能をオンまたはオフにすることで、さまざまなビルドバリエーションがあります。
1)デバッグ
従来、これは特別な特性のない単純なビルドであり、デバッグが容易で予測可能です。これはプラットフォームによって多少異なりますが、信頼性を確保するために、割り当てやバッファサイズなどの追加の余裕がある場合があります。通常、DEBUGやConditional( "Debug")などのコンパイラシンボルが存在するため、デバッグ固有のコードが取り込まれます。これは、特に信頼性や再現性が高い場合に、機能レベルのシンボルがそのままの状態で出荷されるビルドであることがよくあります。懸念。
2)リリース/最適化ビルド
コンパイラーの最適化を有効にすると、コンパイラーのいくつかの低レベルコード生成機能が有効になり、コードに関する仮定に基づいて、コードを高速化または小型化できます。アルゴリズムの選択が適切でない場合、可能な速度の増加は関係ありませんが、集中的な計算の場合、これにより、共通部分式の除去やループのアンロールなどによって十分な違いが生じる可能性があります。ノッチを下げる必要があります。最適化されたコードのコンパイラーのバグも、以前は問題でした。
3)インストルメント済み/プロファイル済みビルド
コードは、関数が呼び出された回数とその関数で費やされた時間を測定する特定のインストルメンテーションコードで構築されています。このコンパイラー生成コードは、分析のプロセスの最後に書き出されます。専用のソフトウェアツールを使用する方が簡単な場合があります。以下を参照してください。このタイプのビルドは出荷されません。
4)安全/チェック済みビルド
すべての「安全弁」は、プリプロセッサシンボルまたはコンパイラ設定を介して有効になります。たとえば、ASSERTマクロは関数のパラメーターをチェックし、イテレーターは変更されていないコレクションをチェックし、カナリアはスタックに入れられて破損を検出し、ヒープ割り当てはセンチネル値(0xdeadbeefは記憶に残る値)で埋められてヒープの破損を検出します。サイトでしか再現できない永続的な問題があるお客様にとって、これは便利なことです。
5)機能の構築
ソフトウェア製品の要件が異なる複数の顧客がいる場合、一般的には、顧客ごとにビルドを行い、テスト時に異なる部分を実行します。たとえば、ある顧客はオフライン機能を望んでおり、別の顧客はオンラインのみを望んでいます。コードのビルド方法が異なる場合は、両方の方法をテストすることが重要です。
ロギングとトレース
したがって、printf()に役立つステートメントをいくつか書き込んだ後、包括的な構造化トレース情報をデータファイルに書き込んでいきます。その後、この情報をマイニングして、ソフトウェアの実行時の動作/特性を理解できます。コードがクラッシュしない場合、または再現に時間がかかる場合は、たとえば、スレッドのリスト、それらの状態遷移、メモリ割り当て、プールサイズ、空きメモリ、ファイルハンドルの数などの画像を用意すると便利です。実際には、アプリケーションのサイズ、複雑さ、およびパフォーマンスの要件に依存しますが、ゲーム開発者は、フレームレートに影響を与える可能性があるため、ゲームの進行中にCPUまたはメモリの使用に「スパイク」がないことを確認する必要があります。この情報の一部はシステムによって維持され、一部はライブラリによって維持され、残りはコードによって維持されます。
その他のツール
これらのシナリオをカバーするために別のビルドを作成する必要があるとは限りません。プロセス構成(Windowsレジストリトリック)によって実行時にいくつかの側面を選択できるため、標準ライブラリよりも優先度の高い代替ライブラリを利用できます。ローダーパスを使用するか、ソフトウェアICEまたは専用デバッガーを使用して、ランタイム特性(Intel v-Tuneなど)についてソフトウェアをプローブします。これらの一部は高額な費用がかかり、一部は無料です-dtrace、Xcodeツール。