★メモリリーク★


ここでは「メモリリーク」について説明します。

malloc関数などでメモリ領域を確保した際に、free関数で確保したメモリを解放しなかった時に発生する危険な状態を指します。

とりあえず、サンプルプログラムを書いてみましょう。

<sample program col035-01>

#include <stdlib.h>

int main(void)
{
    int *p;

    p = (int*)malloc(sizeof(int));

    return 0;
}

このプログラムはfree関数がありません。

コンパイルエラーも無く、普通に実行出来ますので実行してみましょう。

<実行結果>

続行するには何かキーを押してください・・・

特に変わった様子はありませんが、コンピュータ内部ではある事が起こっています。

malloc関数はメモリの領域を確保する関数ですが、その仕組はこうなっています。

まず、ポインタ変数pが用意されます。

      +----------+
    P |          |
      +----------+

次に、malloc関数が呼ばれる訳ですが、malloc関数はヒープ領域というプログラマが自由に扱えるメモリ領域のどこかを確保します。

今回はintサイズ1つ分ですから、私の環境では4バイト分の領域が確保されます。

具体的なアドレスが見たいので、↑のプログラムに少し追加します。

<sample program col035-02>

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int *p;

    p = (int*)malloc(sizeof(int));

    printf("address = %p\n", p);

    return 0;
}

<実行結果>

address = 0029FFB0
続行するには何かキーを押してください・・・

※実行結果は毎回異なる可能性があります。


0029FFB0番地から4バイト分の領域を確保したということです。

図にすると、

           +----------+
  0029FFB0 |          |
           +----------+
  0029FFB1 |          |
           +----------+
  0029FFB2 |          |
           +----------+
  0029FFB3 |          |
           +----------+

これだけのメモリがこのプログラムのために確保され、他のプログラムからは使えないようになります。

そして、先頭アドレスの 0029FFB0 がポインタ変数pに入ります。

      +----------+
    P | 0029FFB0 |
      +----------+

これで、プログラムは終わります。

しかし、0029FFB0番地は確保されたままです。

プログラムが終わっても、この領域は確保され続け、他のプログラムからは使えません。

これが「メモリリーク」という状態です。


「メモリリーク」が発生すると、他のプログラムが使えるメモリが減ります。

もし、大きな領域を確保したままプログラムを終えると、使えなくなるメモリも大きくなり、他のプログラムに支障をきたすようになります。

このプログラムを何度も実行すると、実行すればするほど、使えないメモリが増えていきます。

最悪の場合、コンピュータ自体が停止します。


この最悪のバグを検知するには、特別な方法が必要です。

上のプログラムに次のコードを追加してください。

<sample program col035-02>

#include <stdio.h>
#include <stdlib.h>
#include <crtdbg.h>

int main(void)
{
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

    int *p;

    p = (int*)malloc(sizeof(int));

    printf("address = %p\n", p);

    return 0;
}

とりあえず、実行してみます。

<実行結果>

address = 004AF7D0
続行するには何かキーを押してください・・・

※実行結果は毎回異なる可能性があります。


何も変わったところはありません・・・

「メモリリーク」が発生したかどうかも不明です・・・

実は、実行方法を変えなければ「メモリリーク」を検知出来ないのです。

通常は、デバッグメニューから「デバッグなしで開始」を選択して実行していました。

しかし、バグを見つけるためには「デバッグの開始」を選ばなければなりません。

それでは、「デバッグの開始」を選んで実行してみましょう。

「デバッグなしで開始」と違って、実行後に止まることなく終わってしまいます。

しかし、Visual Studioの下の方に表示されている「出力」ウィンドウを見てください。

※表示されていない人は、「表示メニュー」から「出力」を選んでください。

そこには、以下のメッセージが書かれているはずです。

  Detected memory leaks!
  Dumping objects ->
  {67} normal block at 0x004AF7D0, 4 bytes long.
   Data: <    > CD CD CD CD 
  Object dump complete.

これは、

  004AF7D0番地から4バイト分のメモリーリークが発生した!

というメッセージです。

※番地は環境によって変わります。


malloc関数を使う際には、メモリの解放に注意してください。

free関数を呼び忘れると非常に危険な状態になりますので、malloc関数を使う時は上記のデバッグコードをmain関数の先頭に記述し、デバッグの開始で実行してみてください。


ブラウザの戻るボタンで戻ってください。