ブロックをmallocすると、実際には、要求したよりも少し多くのメモリが割り当てられます。この余分なメモリは、割り当てられたブロックのサイズ、ブロックのチェーン内の次の空き/使用済みブロックへのリンク、場合によっては過去に書き込んだかどうかをシステムが検出するのに役立つ「ガードデータ」などの情報を格納するために使用されます割り当てられたブロックの終わり。また、ほとんどのアロケータは、メモリの合計サイズや開始部分をバイトの倍数に切り上げます(たとえば、64ビットシステムでは、データを64ビット(8バイト)の倍数に整列させる場合があります。アラインされていないアドレスからのデータへのアクセスは、プロセッサ/バスにとってより困難で非効率的である可能性があるため、「パディング」(未使用のバイト)が発生する可能性もあります。
ポインタを解放すると、そのアドレスを使用して、割り当てられたブロックの先頭(通常)に追加された特別な情報が検索されます。別のアドレスを渡すと、ガベージを含むメモリにアクセスするため、その動作は定義されていません(ただし、ほとんどの場合、クラッシュが発生します)
後で、ブロックをfree()してもポインタを「忘れない」と、将来そのポインタを介して誤ってデータにアクセスしようとする可能性があり、動作は定義されていません。次のいずれかの状況が発生する可能性があります。
- メモリは空きブロックのリストに入れられる可能性があるため、メモリにアクセスしても、そこに残したデータがメモリに含まれている可能性があり、コードは正常に実行されます。
- メモリアロケータがメモリの(一部)をプログラムの別の部分に与えた可能性があり、それによっておそらく古いデータ(の一部)が上書きされるため、それを読み取るとガベージが発生し、予期しない動作が発生する可能性がありますまたはコードからクラッシュします。または、他のデータを上書きして、プログラムの他の部分が将来のある時点で奇妙な動作をするようにします。
- メモリがオペレーティングシステムに戻された可能性があります(使用しなくなったメモリの「ページ」をアドレス空間から削除できるため、そのアドレスで使用可能なメモリはなくなります。基本的には未使用の「穴」です。アプリケーションのメモリ内)。アプリケーションがデータにアクセスしようとすると、ハードメモリ障害が発生し、プロセスが強制終了されます。
これが、ポインタが指すメモリを解放した後にポインタを使用しないようにすることが重要である理由です。このためのベストプラクティスは、メモリを解放した後にポインタをNULLに設定することです。これは、NULLを簡単にテストできるためです。 NULLポインタを介してメモリにアクセスしようとすると、動作は悪くなりますが一貫性があり、デバッグがはるかに簡単になります。