1. ホーム
  2. Qt

valgrindは、メモリリークに関する5つの研究を報告しています。

2022-02-23 21:15:06

概要

valgrindは、Linuxでプログラムをデバッグし、メモリリークを発見するための一般的なツールです。 確実に失われたもの、直接失われたもの、失われた可能性のあるもの、まだ到達可能なもの、そして抑制されたものです。私は仕事の合間にこの5種類のメモリリークの原因や違いについて勉強し、覚えておくためにこの記事を書きました。

<スパン テスト環境

Linux 2.6.18-194.el5 x86_64

<スパン valgrind-3.5.0

<スパン 公式の解説と分析です。

http://valgrind.org/docs/manual/faq.html#faq.deflost より取得

5.2.Memcheck のメモリリーク検出器で、"discely lost"、"directly lost"、" possibly lost"、" still reachable、および "suppressed" はどう違いますか。
詳しくは、ユーザーマニュアルの「Memcheck」の項に記載されています。
要するに
プログラムがメモリをリークしていることを意味します。
間接的に失われたもの("indirectly lost")とは、プログラムがポインタベースの構造でメモリをリークしていることを意味します。(例えば、二分木のルートノードが " definitely lost" である場合、すべての子ノードは " indirectly lost" になります)。もし、"discertain lost"のリークを修正すれば、"indirectly lost"のリークはなくなるはずです。
ポインターで変わったことをしていて、そのポインターを指す可能性がある場合を除き、プログラムがメモリをリークしていることを意味します。 これらのレポートを表示したくない場合は、--show-possibly-lost=no を使用してください。
quot;still reachable"は、あなたのプログラムはおそらく大丈夫で、解放できるはずのメモリが解放されなかったことを意味します。このようなレポートを見たくなければ、--show-reachable=yes を使ってください。
quot;suppressed"は、リークエラーが抑制されたことを意味します。デフォルトのサプレッションファイルには、いくつかのサプレッションがあります。抑制されたエラーは無視することができます。

<スパン "間違いなく負けました"。確認が取れなくなった。プログラム中にメモリリークがあり、早急に修正する必要があります。動的に割り当てられたメモリがプログラムの終了時に解放されず、プログラム内のどのポインタ変数からもアクセスできない場合 <スパン このエラーは、動的に割り当てられたメモリブロックがプログラム終了時に解放されず、プログラム内のどのポインタ変数からもアクセスできない場合に報告されます。

<スパン <スパン <スパン "間接的に失われた"。間接的に失われた。このエラーは、ポインタ・メンバを含むクラスまたは構造体を使用するときに報告されることがあります。 この種のエラーは直接修正する必要はなく、常に関連する を修正するだけです。 "間違いなく失われた"。例として、私のルーチンをご覧ください。

<スパン <スパン <スパン "possibly lost":紛失した可能性がある。と同じと考えるべきケースがほとんどです。 <スパン を要求しているため、間違いなく紛失します。 へのポインタを作成しない限り、できるだけ早く修正する必要があります。 動的に割り当てられたメモリブロック(ただし これは メモリブロックの開始アドレス )を得るための演算を行う。 これは ブロックのメモリーを解放します。 の例は、私のルーチンの中で見ることができます。 動的に割り当てられたメモリーブロックがプログラム終了時に解放されず、プログラム内のどのポインター変数からもアクセスできない場合、そのブロックの上にある このエラーは、メモリブロックの開始アドレスがプログラム終了時に解放されていないが、データの一部にアクセス可能な場合に報告されます。

<スパン <スパン <スパン <スパン <スパン <スパン <スパン <スパン <スパン "still reachable": アクセス可能で、失われないが解放もされない。正常に終了すればプログラムがクラッシュすることはありませんが、長時間実行するとシステムリソースを使い果たす危険性があるため、作者は修正することを推奨しています。 プログラムが正常に終了せずクラッシュしている場合(不正なアドレスにアクセスしてクラッシュするなど)、とりあえず無視し、先に修正することにより プログラムがエラーでクラッシュし、その後再テストを行う。

<スパン "suppressed"。解決済みです。登場 <スパン メモリリークが発生したが、システムが自動的に処理した。このタイプの エラー . ルーチンでこの種のエラーを引き起こすことができず、公式の説明ではOSの で処理されます。 または valgrindは、私も遭遇したことがありません。なので、無視してください〜。

<スパン テストの手順

<スパン ソースコード(C++)。

#include "stdio.h"
#include "stdlib.h"

class c1
{
private:
	char *m_pcData;

public:
	c1();
	~c1();
};

c1::c1()
{
	m_pcData=(char*)malloc(10);
}

c1::~c1()
{
	if(m_pcData) delete m_pcData;
}
 
char *Fun1()//definitely lost
{
	char *pcTemp;

	pcTemp=(char*)malloc(10);
	return pcTemp;
}

char *Fun2()//still reachable
{
	static char *s_pcTemp=NULL;

	if(s_pcTemp==NULL) s_pcTemp=(char*)malloc(10);

	return NULL;
}

char *Fun3()//possibly lost
{
	static char *s_pcTemp;
	char *pcData;

	pcData=(char*)malloc(10);
	s_pcTemp=pcData+1;

	return NULL;
}

int Fun4()//definitely and indirectly lost
{
	c1 *pobjTest;

	pobjTest=new c1();

	return 0;
}

char *Fun5()//possibly lost but no need of repair,repair the breakdown then no memory leak
{
	char *pcData;
	int i,*piTemp=NULL;

	pcData=(char*)malloc(10);
	pcData+=10;
	for(i=0;i<10;i++)
	{
		pcData--;
		*pcData=0;
	
		if(i==5) *piTemp=1;//create a breakdown
	}
	free(pcData);

	return NULL;
}

int main()
{
	printf("This program will create various memory leaks,use valgrind to observe it.\n");
	printf("Following functions are bad codes,don\'t imitate.\n");
	printf("Fun1\n");
	Fun1();
	printf("Fun2\n");
	Fun2();
	printf("Fun3\n");
	Fun3();
	printf("Fun4\n");
	Fun4();
	printf("Fun5\n");
	Fun5();
	printf("end\n");

	return 0;
}



valgrindで実行した結果。

[root@localhost valtest]# valgrind --tool=memcheck --leak-check=yes . /valtest 
メモリエラー検出ツール ==29240== Memcheck
==29240== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==Valgrind-3.5.0 と LibVEX を使用、著作権情報のため -h で再実行
==29240== コマンドを実行します。. /valtest
==29240== 
このプログラムは様々なメモリリークを発生させるので、valgrindで観測してください。
このプログラムは様々なメモリリークを発生させるので、valgrindで観測してください。
ファン1
ファン2
ファン3
ファン4
ファン5
==サイズ 4 の無効な書き込みです。
==29240== at 0x4007BE: Fun5() (main.cpp:73)
0x40086E による ==29240==: メイン (main.cpp:93)
==アドレス0x0がスタックされていない、マロードされていない、または(最近)解放されていない。
==29240== 
==29240== 
==シグナル 11 (SIGSEGV) のデフォルトアクションでプロセスが終了します。
==アドレス 0x0 のマップされた領域内にアクセスできない。
==29240== at 0x4007BE: Fun5() (main.cpp:73)
0x40086E による ==29240==: メイン (main.cpp:93)
==29240== もし、これがスタックの結果として起こったと考えるなら
==29240== プログラムのメインスレッドでオーバーフローが発生(可能性は低いが
==29240== 可能性あり) のサイズを大きくしてみるのも手です。
==メインスレッドスタックは --main-stacksize= フラグで指定します。
==この実行で使用されたメインスレッドスタックサイズは10485760でした。
==29240== 
==29240== ヒープまとめ。
==終了時に使用中:6ブロック58バイト
==ヒープ使用量の合計です。6つの割り当て、0つの解放、58バイトの割り当て
==29240== 
==19240= 1 ブロック中の 10 バイトが失われた可能性がある(損失記録 2 of 6
==29240== at 0x4A05E1C: malloc (vg_replace_malloc.c:195)
0x4006D9 による ==29240==: Fun3() (main.cpp:46)
0x400850 によって ==29240==: メイン (main.cpp:89)
==29240== 
==19240= 1 ブロック中の 10 バイトが失われた可能性がある。
==29240== at 0x4A05E1C: malloc (vg_replace_malloc.c:195)
0x400795 による ==29240== です。Fun5() (main.cpp:66)
0x40086E による ==29240==: メイン (main.cpp:93)
==29240== 
==19240= 1 ブロックの 10 バイトが確実に失われる(損失記録 5 of 6
==29240== at 0x4A05E1C: malloc (vg_replace_malloc.c:195)
==29240== by 0x40072D: Fun1() (main.cpp:28)
0x400832 によって ==29240==: メイン (main.cpp:85)
==29240== 
==19240= 1ブロック中の18(直接8、間接10)バイトが消失記録6/6で確実に失われる
==29240== at 0x4A0666E: operator new(unsigned long) (vg_replace_malloc.c:220)
==29240== by 0x4007F0: Fun4() (main.cpp:56)
0x40085F による ==29240==: メイン (main.cpp:91)
==29240== 
==29240== リークまとめ。
==19240== 確実に失われたもの: 2 ブロックで 18 バイト
==間接的に損失:1ブロックに10バイト
==29240= 失われた可能性: 2 ブロックで 20 バイト
==29240== まだ到達可能です。1ブロックに10バイト
==抑制されています。0 バイト、0 ブロック
==到達可能なブロック(ポインタが見つかったもの)は表示されません。
==29240== 表示させるには、次のように再実行します。--リークチェック=フル --show-reachable=yes
==29240== 
==検出されたエラーと抑制されたエラーの数については、以下のように再実行します。-v
==ERROR SUMMARY: 5 つのコンテキストから 5 つのエラー (抑制: 4 つのコンテキストから 4 つのエラー)
段落エラー

That's it, end -----------------------------------------------------EOB-------------------------------------------------------