2012年11月14日水曜日

メモリリークを調べる

ぐるぐるまわるプログラムを書いてるとだんだんメモリ使用量が増えてくポップな現象いわゆるメモリリークが起きることがあるので調査可能なBoehm GCというライブラリを紹介します.

○ インスコ

Boehm GCのソースはここにあります.
./configure → make → make install のコンボでインストールできます.

○ 使う

4個くらいのナンセンスなプログラムを例にぐるメポップの見つけ方の例を示します.

(0) 準備
define GC_DEBUG
include "gc.h"
define malloc(n) GC_MALLOC(n)
define calloc(m,n) GC_MALLOC((m)*(n))
define free(p) GC_FREE(p)
define realloc(p,n) GC_REALLOC((p),(n))
define CHECK_LEAKS() GC_gcollect()
デバッグ用に上の文を書いときます.プログラム内でmallocした領域がBoehmの管理下に入ります. ちなみにこれを導入したプログラムをgccでコンパイルするときのオプション例は以下.
gcc -o TS TS.c -I/usr/local/include -L/usr/lib -lgc

(1) ループ内でmallocしたアドレスを何度も同じポインタ変数に代入しよう
int main(void)
{
  GC_find_leak = 1;
  
  int i; int *p;
  for(i=0;i<100;i++){
    p = (int *)malloc(100*sizeof(int));
  }

  exit(0);
  return 0;
}
GC_find_leak=1は ぐるポ検出モードです. return の前に exit してるのは return した瞬間にガベコレが働いていろいろうるさかったからです.Let Mr.Exit shut him upということです. とりあえずこれでちゃんと検出できました.やったね!v(^o^)v
実行結果はリークポイントが行数で表示されます.長いので端折りますが. ちなみにループが1回だと検出はしません.


(2) freeしないvoidのmalloc用関数を呼び出してみよう
void isalloc(int n)
{
  int *p;
  p = (int *)malloc(n*sizeof(int));
}

int main(void)
{
  GC_find_leak = 1;

  int i;
  for(i=0;i<100;i++){
    isalloc(100);
  }

  exit(0);
  return 0;
}
検出.これはループ呼び出し1回だけでも検出します.


(3) (2)のプログラムでちゃんとfreeしてみよう
void isalloc(int n)
{
  int *p;
  p = (int *)malloc(n*sizeof(int));
  free(p);
}
検出せず.

(4) (2)のプログラムで取得した領域をstaticなポインタ配列に代入して保持しよう
void isalloc(int n)
{
  int *p;
  static int num_hist=0;
  static int **p_hist;
  
  p = (int *)malloc(n*sizeof(int));
  p_hist = (int **)realloc(p_hist, sizeof(p_hist)+n*sizeof(int *));
  p_hist[num_hist++] = p;
}
これも検出せず.

ということで,領域のアドレスを保持したポインタ変数が生きてる場合は検出しませんが,解放してない領域のアドレスが手の届かないとこにいっちゃってfreeできない場合に有効みたいです.要するにこの書き方だと解放されずに上書きされたもののみ検出します.

役立つのか微妙ですが興味ある人はお役立てください.

0 件のコメント :

コメントを投稿