プログラミング言語Cで開発を行う際、プログラムのメモリ管理は非常に重要なポイントです。メモリの解放漏れ(メモリリーク)やアクセス違反は、予期せぬバグやクラッシュを引き起こす原因となります。これらの問題を未然に防ぐのに、valgrindは結構便利です。
Valgrindとは?
Valgrindは、プログラムのメモリ使用状況を解析するためのツールです。メモリリーク、アクセス違反、不正なメモリアクセスなどを検出し、詳細な情報をレポートとして出力してくれます。Linux系OS(Ubuntu, CentOS, Arch Linuxなど)で利用可能で、C/C++のデバッグには欠かせないツールの一つです。
僕も全然詳しくないですが、leaksコマンドが使えない環境でC言語を使う必要がある時、調べて見つけました。しかも使いこなせたら結構強そう
インストール方法
まずは、Valgrindをインストールしましょう。
sudo apt-get install valgrind
Valgrindの基本的な使い方
コマンドの概要
Valgrindを使ってプログラムの実行を追跡するためには、以下のコマンドを使用します。
valgrind [オプション] ./実行ファイル [引数]
よく使うオプション
-
--leak-check=full
:メモリリークに関する詳細な情報を表示します。 -
--track-origins=yes
:未初期化メモリの使用箇所を特定します。 -
--show-leak-kinds=all
:全ての種類のメモリリーク(確保したが解放されていないメモリ、無効な解放など)を表示します。
これらのオプションを組み合わせて、メモリリークをチェックしてみましょう。
メモリリークのチェック方法
以下のようなメモリリークのある簡単なCプログラムを例にして、Valgrindを使ったメモリチェックを実行します。
// memory_leak_example.c
#include <stdio.h>
#include <stdlib.h>
void create_memory_leak() {
int *leak = (int*) malloc(10 * sizeof(int));
leak[0] = 42;
// メモリを解放し忘れている
}
int main() {
create_memory_leak();
return 0;
}
上記のプログラムでは、malloc
で確保したメモリがfree
されていないため、メモリリークが発生します。このプログラムをコンパイルし、Valgrindを使ってチェックしてみましょう。
gcc -g -o memory_leak_example memory_leak_example.c
valgrind --leak-check=full --track-origins=yes --show-leak-kinds=all ./memory_leak_example
出力結果の確認
Valgrindの出力結果を確認すると、以下のようなメッセージが表示されます。
==12345== Memcheck, a memory error detector
==12345== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==12345== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==12345== Command: ./memory_leak_example
==12345==
==12345== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==12345== at 0x4C2B975: malloc (vg_replace_malloc.c:299)
==12345== by 0x109156: create_memory_leak (memory_leak_example.c:6)
==12345== by 0x109179: main (memory_leak_example.c:11)
==12345==
==12345== LEAK SUMMARY:
==12345== definitely lost: 40 bytes in 1 blocks
==12345== indirectly lost: 0 bytes in 0 blocks
==12345== possibly lost: 0 bytes in 0 blocks
==12345== still reachable: 0 bytes in 0 blocks
==12345== suppressed: 0 bytes in 0 blocks
==12345==
==12345== For counts of detected and suppressed errors, rerun with: -v
==12345== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
出力の解釈
-
definitely lost
は、確保したが解放されなかったメモリを指します。上記の例では、malloc
で確保されたメモリ(40バイト分)が解放されずに失われていることが示されています。 -
at 0x4C2B975: malloc
の部分は、メモリを確保した関数malloc
の呼び出し元を特定しています。 -
by 0x109156: create_memory_leak
は、create_memory_leak
関数内のどの行でメモリを確保したか(memory_leak_example.c:6
)を示しています。
メモリリークの修正
上記のプログラムを修正して、メモリリークを解消してみましょう。create_memory_leak
関数にfree
を追加します。
// memory_leak_example.c
#include <stdio.h>
#include <stdlib.h>
void create_memory_leak() {
int *leak = (int*) malloc(10 * sizeof(int));
leak[0] = 42;
free(leak); // メモリを解放
}
int main() {
create_memory_leak();
return 0;
}
再度、コンパイルしてValgrindを実行します。
gcc -g -o memory_leak_example memory_leak_example.c
valgrind --leak-check=full --track-origins=yes --show-leak-kinds=all ./memory_leak_example
この修正版プログラムでは、メモリリークが解消され、Valgrindからのエラー出力も表示されません。
==12345== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
まとめ
C言語のメモリチェックには、valgrindを使うという手もあります。
valgrindを使う時は、--leak-check=full
や--track-origins=yes
、--show-leak-kinds=all
のオプションが便利らしいです。