メモリーリークの検出:mtrace , valgrind
以前の記事にもLinuxでのメモリーリークの検出に関する事を書いたのですが、もう少し一般的なやり方を紹介しましょう(というより、自分で毎回忘れるので備忘録として・・・)。
【mtraceを使う方法】
まず、mtraceを使う方法です。リークのテストを開始したい場所でmtrace()をコールし、終了したい場所でmuntrace()をコールするようにします。
#include <stdio.h>
#include <stdlib.h>
char *test()
{
char *test=malloc(10);
return(test);
}
int main()
{
char *ptr;
mtrace();
ptr=test();
//*(ptr+10)='\0';
//free(ptr);
muntrace();
return(0);
}
-gつきでコンパイルします。
# cc -g test.c -o test
MALLOC_TRACE環境変数をセットします。
# export MALLOC_TRACE=./mtrace.log
実行します。
# ./test
結果を見ます。
# mtrace ./test ./mtrace.log
Memory not freed:
-----------------
Address Size Caller
0x0a028378 0xa at /tmp/test.c:5
test.cの5行目の「char *test=malloc(10);」で確保したものが解放されていない、と検知してくれました。
【valgrindを使う方法】
続いて、valgrindを使う方法です。valgrindは標準状態ではインストールされていないと思いますので、ソースから、またはパッケージでインストールしておいてください。
こちらはソースに加工は不要です。-gつきでコンパイルしておきます。
実行時に、以下のようにvalgrindを実行します。
# valgrind --tool=memcheck --leak-check=yes ./test
==24658== Memcheck, a memory error detector for x86-linux.
==24658== Copyright (C) 2002-2004, and GNU GPL'd, by Julian Seward et al.
==24658== Using valgrind-2.2.0, a program supervision framework for x86-linux.
==24658== Copyright (C) 2000-2004, and GNU GPL'd, by Julian Seward et al.
==24658== For more details, rerun with: -v
==24658==
==24658==
==24658== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 12 from 1)
==24658== malloc/free: in use at exit: 522 bytes in 2 blocks.
==24658== malloc/free: 3 allocs, 1 frees, 874 bytes allocated.
==24658== For counts of detected errors, rerun with: -v
==24658== searching for pointers to 2 not-freed blocks.
==24658== checked 1368972 bytes.
==24658==
==24658== 10 bytes in 1 blocks are definitely lost in loss record 1 of 2
==24658== at 0x1B904984: malloc (vg_replace_malloc.c:131)
==24658== by 0x80483E3: test (test.c:5)
==24658== by 0x8048414: main (test.c:12)
==24658==
==24658== LEAK SUMMARY:
==24658== definitely lost: 10 bytes in 1 blocks.
==24658== possibly lost: 0 bytes in 0 blocks.
==24658== still reachable: 512 bytes in 1 blocks.
==24658== suppressed: 0 bytes in 0 blocks.
==24658== Reachable blocks (those to which a pointer was found) are not shown.
==24658== To see them, rerun with: --show-reachable=yes
いろいろ出ますが、
==24658== 10 bytes in 1 blocks are definitely lost in loss record 1 of 2
==24658== at 0x1B904984: malloc (vg_replace_malloc.c:131)
==24658== by 0x80483E3: test (test.c:5)
==24658== by 0x8048414: main (test.c:12)
ここで、test.cの5行目で確保したものが解放されていないとわかります。
valgrindは他にも豊富な機能があり、リーク以外にも様々な調査が可能ですので、興味がある方は調べてみると良いでしょう。
mtraceとvalgrindを比べると、一般的にはvalgrindの方が多機能で便利だと思いますが、mtraceの便利なところは、ソース内でどこからどこの間でリークを調べたいかを指定できる点です。valgrindはプロセス全体の起動から終了までを調べることしかできませんので、部分的な検査は面倒かも知れません。また、mtraceは一般的なLinux環境であれば、そのままの状態でほぼ間違いなく使えますが、valgrindはインストールが必要です。注意点としては、mtraceはスレッドセーフではないことです。マルチスレッドのプロセスを検査する場合はvalgrindを使いましょう。
他にもフリーのツールはありますし、有償のツールもありますが、とりあえずこの2つを使えれば大体間に合うと思います。C言語でのプログラミングはバッファオーバーランとかリークなど、様々な危険がありますが、組み込み用途では主流ですし、高性能なプログラムを作りたい場合にも、自分の作ったとおりに動いてくれますので、やっぱりまだまだ欠かせません。危険な部分はツールを使って確認するようにし、C言語の良いところを活かしたプログラムを生み出しましょう!