ヒープ内で割り振られたメモリーの各ブロックは、割り振りを行う関数から戻される アドレスから始まるデータ域と、データ域に隣接する制御域からなり、 メモリーを割り振り解除したときにはメモリー管理関数によってメモリーは適切に解放される必要 があります。ヒープ内の制御構造を 上書きした場合 (例えば、配列に割り振られた境界を超えて要素を書き込んだり、 ストリングをコピーした先の割り振り済みメモリーのブロックが小さすぎる場合)、 他の割り振り済みブロックのデータ域が上書きされていない場合でも、 制御情報が破壊され、プログラムが正しく機能しなくなる可能性があります。
ヒープ・エラーが起こった場所を探索するときには、以下の点を考慮してください。
ヒープ・エラーを検出するために、ヒープ・チェック版のメモリー管理関数を使用するようにプログラムをコンパイルすることができます (-qheapdebug コンパイラー・オプションについては、デバッグ・コンパイラー・オプションに関する関連トピックを参照してください)。この オプションを使用してコンパイルしたプログラムを実行すると、メモリー管理関数の 呼び出しのたびに、デフォルト・ヒープでヒープ・チェックが行われます。このヒープ・チェックには、 ヒープ内で割り振られた各メモリー・ブロックの制御構造のチェック、 どれも上書きされていないことの確認が含まれます。エラーが検出された場合、 プログラムは終了し、ヒープ破壊が発生したアドレス、有効なヒープ状態が最後に検出された ソース・ファイルと行番号、メモリー・エラーが検出されたソース・ファイルと行番号の情報が、 標準エラーに書き込まれます。
ヒープ・チェックは、 各実行可能ファイルが使用するデフォルト・ヒープに対してのみ使用可能にされます。デバッグ版の メモリー管理関数からヒープ破壊の報告がなく、それでも問題があると考えられる場合、その他のヒープを追加使用し、それらのヒープを 破壊している可能性があります。
エラーを起こしているヒープが デフォルトのヒープであることが判明している場合に限り、 ヒープが有効だった最後の行と破壊が発生した最初の行との間を 次第に狭めていくことによって、デバッガー内から、ヒープ・エラーの原因を ピンポイントで特定することができます。検索の有効範囲を狭めるためには、 実行コマンド、ステップ・コマンド、行ブレークポイントおよび関数ブレークポイント、 および「停止時にヒープ・チェックを実行」設定を組み合わせて使用します。 この設定については、関連トピックを参照してください。
意味的に正しくないプログラムの 場合、「停止時にヒープ・チェックを実行」は、 それを使用したために、プログラムがスタックのデータに不正にアクセスする、さまざまな異なる結果に なることがあります。これは、「停止時にヒープ・チェックを実行」を 使用すると、デバッグ対象のプロセスおよびスレッドが、 実行が停止するたびにヒープ・チェック関数を呼び出し、このヒープ・チェック関数が、 スタックの安全な領域に対して、そのスタック・フレームで領域の一部を上書きするという 影響を与えてしまうためです。例えば、ローカル変数の アドレスを戻すような関数が呼び出されるとすると、そのローカル変数の内容は、呼び出し側関数からアクセス可能であり、 呼び出された関数によって使用されるスタック・フレームが 後続の呼び出しで上書きされない限り変わりません。しかし、「停止時にヒープ・チェックを実行」が使用可能にされている間に、 呼び出される側の関数からステップ・リターンを発行する場合、 呼び出される側の関数から戻るとすぐにヒープ・チェック関数が呼び出され、 戻されたポインターが指すメモリーは、ヒープ・チェック関数のスタック・フレームによって上書きされている可能性があります。
デバッガー内での ヒープ・チェックは、ステップ・コマンドに対して高いオーバーヘッド・コストがかかります。 これは、各ステップの後にヒープがチェックされるためです。コードのうち大きなセクションをステップスルーする場合や ブレークポイントで頻繁に停止する場合で、デバッグのパフォーマンスが遅すぎると思われる場合は、 ヒープ・エラーを引き起こしていると疑われる領域でのみ「停止時にヒープ・チェックを実行」を オンにしてみてください。