リークの検出
memcheck の基礎です。
「リークの検出」はCoddyKit上の無料C Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C Academyコースには全4レッスンが含まれています。
リークとは
メモリリークとは、malloc、calloc、reallocでヒープメモリを確保した後、freeを呼び出す前に、そのメモリへのポインターをすべて失うことです。
そのブロックはプロセスが終了するまで確保されたままですが、到達できなくなります。長時間稼働するプログラムでは、リークが蓄積してメモリを使い果たします。
最小限のリーク
このプログラムは40バイトのブロックを1つリークします。
ポインターpはローカル変数です。mainが戻るとpは消えますが、指していたヒープブロックは解放されません。
#include <stdlib.h>
int main(void) {
int *p = malloc(10 * sizeof(int));
p[0] = 1;
return 0; /* never free(p) */
}memcheckの実行
memcheckはデフォルトのツールなので、ツール名を省略できます。
--leak-check=fullを追加すると、リークした確保ごとにスタックトレースが表示されます。
gcc -g -O0 -o leak leak.c
valgrind --leak-check=full ./leakリーク概要
終了時にValgrindはLEAK SUMMARYを出力します。上記のプログラムでは、おおむね次のように表示されます。
definitely lost: 40 bytes in 1 blocks
トレースは正確なmallocの呼び出し箇所を示すため、どのメモリ確保が解放されなかったのかを正確に把握できます。
4つのリーク分類
memcheckは失われたメモリを4つに分類します。
- definitely lost — ポインターが残っていない。真のリーク
- indirectly lost — definitely lostのブロックを通してのみ到達可能
- possibly lost — 内部を指すポインターだけが残っている
- still reachable — 終了時にもポインターは存在するが、解放されていない
Definitely lostとStill reachableの違い
definitely lostは緊急性の高い分類です。プログラムの実行中に、そのバイト列を回収することはできません。
still reachableはそれほど深刻ではありません。終了時にブロックはリークしていますが、グローバルポインターまたはstaticポインターが参照し続けています。そのため、通常は一度だけ確保し、単に解放しなかったメモリです。
間接的なリーク
リンク構造の先頭を失うと、すべてのノードに到達できなくなります。
先頭はdefinitely lostとして表示され、残りはindirectly lostとして表示されます。根本原因である失われた先頭を修正すれば、すべてを回収できます。
struct Node { int v; struct Node *next; };
struct Node *make(void) {
struct Node *h = malloc(sizeof *h);
h->next = malloc(sizeof *h);
h->next->next = NULL;
return h;
}
/* if the caller drops the returned head, both nodes leak */修正版
確保したメモリは解放してください。このバージョンでは何もリークしません。
ValgrindではAll heap blocks were freed -- no leaks are possibleと報告されます。
#include <stdlib.h>
int main(void) {
int *p = malloc(10 * sizeof(int));
p[0] = 1;
free(p);
return 0;
}メモリ確保回数の確認
リークがなくても、HEAP SUMMARYからプログラムがどれだけメモリを使用したかが分かります。
total heap usage: 1 allocs, 1 frees, 40 bytes allocated
allocsとfreesが一致していれば、クリーンな実行です。一致しない場合は、何かが解放されずに残っている最初の手掛かりになります。
到達可能なブロックの表示
デフォルトでは、memcheckはstill reachableなブロックの詳細を一覧表示しません。これらも調査するには、次を追加します。
--show-leak-kinds=all
これによりすべての分類についてトレースが表示され、終了前にすべてを完全に解放するプログラムを目指す場合に役立ちます。
valgrind --leak-check=full --show-leak-kinds=all ./leakエラーパスでのリーク
最も見つけにくいリークは、早期リターンするパスに潜んでいます。ここでは、2回目のメモリ確保に失敗すると、最初のブロックがリークします。
通常のテストではこのような分岐が実行されることはほとんどありませんが、memcheckはそのパスが実行されるたびに検出します。エラー時に戻る前には、保持しているメモリを必ずすべて解放してください。
char *a = malloc(100);
char *b = malloc(100);
if (!b) {
/* bug: a is leaked here */
return -1;
}
/* fix: free(a); before returning */理解度チェック
最も緊急に対処すべきリークの分類を選んでください。
まとめ
memcheckでリークを検出できるようになりました。
-gでコンパイルしたバイナリに対してvalgrind --leak-check=full ./progを実行する- LEAK SUMMARYとHEAP SUMMARYを確認する
- definitely lostを優先し、間接的なリークをたどって根本原因を特定する
--show-leak-kinds=allを使ってstill reachableなブロックも調査する
次は、不正なメモリアクセスについて学びます。
よくある質問
「リークの検出」レッスンは無料ですか?
はい。「リークの検出」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C Academyコースには全4レッスンが含まれています。
「リークの検出」で何を学びますか?
memcheck の基礎です。 ブラウザで直接実行するハンズオンコードでC Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「リークの検出」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC Academyレッスンでコードを書いて実行できますか?
はい。すべてのC Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。