C ++コード/プロジェクトでメモリリークを見つける方法


180

私はWindowsプラットフォームのC ++プログラマーです。Visual Studio 2008を使用しています。

通常、コードにメモリリークが発生します。

通常、コードを検査することでメモリリークを見つけますが、面倒で、常に良い方法とは限りません。

私は有料のメモリリーク検出ツールを買う余裕がないので、メモリリークを回避するための最善の方法を提案してほしいと思いました。

  1. プログラマがメモリリークを見つける方法を知りたい。
  2. プログラムでメモリリークが発生しないようにするための標準や手順はありますか?

29
「私は通常、メモリリークのあるコードになってしまいます。」自動変数、コンテナー、およびスマートポインターを使用する場合(およびスマートポインターを使用するためのベストプラクティスに従う場合)、メモリリークは非常にまれです。覚えておいて、ほとんどの場合、あなたは自動リソース管理を使用する必要があります
James McNellis、2011年


1
@Hostile Fork:「通常、メモリリークのあるコードになるのをどのように回避できるか」は、これらの回答ではカバーされていません。
ドクターブラウン

2
@Doc Brown:それも調べたくありませんでしたが、stackoverflow.com
questions / 45627 /…

1
DIYリークディテクター:疑わしいコードを無限ループに入れてタスクマネージャーを開くことができます。通常、小さなリークでも数秒または数分でメモリがいっぱいになります(コードの複雑さとCPUによって異なります)。それが起こらない場合、そのコードはおそらくリークしていません。
Hello World

回答:


270

指示

必要なもの

  • C ++の習熟度
  • C ++コンパイラ
  • デバッガーおよびその他の調査ソフトウェアツール

1

オペレーターの基本を理解する。C ++オペレーターnewはヒープ・メモリーを割り振ります。deleteオペレータは、ヒープメモリを解放します。すべてのについてnewdelete割り当てた同じメモリを解放するようにを使用する必要があります。

char* str = new char [30]; // Allocate 30 bytes to house a string.

delete [] str; // Clear those 30 bytes and make str point nowhere.

2

削除した場合にのみ、メモリを再割り当てします。以下のコードstrでは、2番目の割り当てで新しいアドレスを取得します。最初のアドレスは回復不能に失われ、それが指している30バイトも失われます。今、それらを解放することは不可能であり、あなたはメモリリークを持っています:

char* str = new char [30]; // Give str a memory address.

// delete [] str; // Remove the first comment marking in this line to correct.

str = new char [60]; /* Give str another memory address with
                                                    the first one gone forever.*/

delete [] str; // This deletes the 60 bytes, not just the first 30.

これらのポインターの割り当てに注意してください。すべての動的変数(ヒープに割り当てられたメモリ)は、ポインターに関連付ける必要があります。動的変数がそのポインターから分離されると、消去できなくなります。この場合も、メモリリークが発生します。

char* str1 = new char [30];

char* str2 = new char [40];

strcpy(str1, "Memory leak");

str2 = str1; // Bad! Now the 40 bytes are impossible to free.

delete [] str2; // This deletes the 30 bytes.

delete [] str1; // Possible access violation. What a disaster!

4

ローカルポインタに注意してください。関数で宣言したポインターはスタックに割り当てられますが、ポインターが指す動的変数はヒープに割り当てられます。削除しないと、プログラムが関数を終了した後も保持されます。

void Leak(int x){

char* p = new char [x];

// delete [] p; // Remove the first comment marking to correct.

}

5

「削除」の後の角括弧に注意してください。delete単独で使用して、単一のオブジェクトを解放します。使用delete []ヒープの配列を解放するために、角括弧で。次のようなことはしないでください。

char* one = new char;

delete [] one; // Wrong

char* many = new char [30];

delete many; // Wrong!

6

リークがまだ許可されている場合-私は通常、deleakerでそれを探しています(ここで確認してください:http ://deleaker.com )。


3
質問コメントで申し訳ありませんが、ポインターのない関数パラメーターについてはどうですか?someFunction("some parameter")私は削除しなければならないの"some parameter"ではsomeFunction関数呼び出しの後、またはこれらの自動的に削除されますか?
19greg96

1
Deleakerへのリンクをありがとう、これはVisual Studioにきちんと統合された本当に便利なツールです。私はそれを使用して多くの時間を節約できました。私がメモリを割り当て、それを解放しなかった行を指摘しました。すごい。そして、私が見つけた他のメモリリークファインダーと比較して、それは安価です。
this.myself

@ john smith plz explanケース3と同様のケースを処理する適切な方法は何か。str2 = str1; //悪い!現在、40バイトを解放することは不可能です。str 1を削除する方法??
Nihar

1
char *、int、floatなどの値の型を使用し、Vector、CStringのような構造体を使用し、「new」演算子をまったく使用しない場合、メモリリークは発生しませんが、正しいですか?
123iamking 2016年

14年近くc ++に触れていないと言っているだけです...しかし、私が持っているときに読んでいるc ++の本のおかげで、これをすべて行う方法を理解し、覚えていることを誇りに思います。 mはc#で退屈しています。その本はスコット・ミッチェルのEffective C ++です。その本を愛してくれた神様。スコット、ありがとう!
JonH 2016年

33

コードでいくつかの手法を使用して、メモリリークを検出できます。最も一般的で検出するための最も簡単な方法は、マクロたとえば、DEBUG_NEWを定義などの定義済みマクロと一緒に、それを使用する、である__FILE____LINE__あなたのコードのメモリリークを見つけるために。これらの定義済みマクロは、メモリリークのファイルと行番号を示します。

DEBUG_NEWは単なるMACROであり、通常は次のように定義されます。

#define DEBUG_NEW new(__FILE__, __LINE__)
#define new DEBUG_NEW

そのため、どこで使用newしても、プログラムのメモリリークを特定するために使用できるファイルと行番号を追跡できます。

そして__FILE____LINE__されているマクロを事前に定義され、あなたがそれらを使用します。ここで、それぞれのファイル名と行番号に評価します!

DEBUG_NEWを他の興味深いマクロと共に使用する手法を非常に美しく説明する次の記事を読んでください。

クロスプラットフォームのメモリリークディテクタ


Wikpediaから、

Debug_newは、メモリの割り当てと割り当て解除の呼び出しをインターセプトするために、オペレーターの新規およびオペレーターの削除をオーバーロードまたは再定義するC ++の手法を指し、メモリ使用量のプログラムをデバッグします。多くの場合、DEBUG_NEWという名前のマクロの定義を含み、newをnew(_ FILE _、_ LINE _)のようなものにして、割り当てに関するファイル/行情報を記録します。Microsoft Visual C ++は、Microsoft Foundation Classesでこの手法を使用しています。このメソッドを拡張して、一部のプラットフォームでファイル/行情報を表示しながらマクロの再定義を使用しないようにする方法がいくつかあります。この方法には多くの固有の制限があります。これはC ++にのみ適用され、mallocなどのC関数によるメモリリークをキャッチできません。ただし、より完全なメモリデバッガーソリューションと比較すると、使用方法は非常に簡単で、非常に高速です。


4
これ#defineはオーバーロードを混乱さoperator newせ、コンパイラエラーを生成します。あなたがそれを克服することに成功したとしても、それでもオーバーロードされた関数は扱われません。テクニックは優れていますが、多くのコード変更が必要になる場合があります。
iammilind

1
@iammilind:もちろん、この手法はすべての問題を完全に解決するわけではなく、すべての状況に適用できるとは限りません。
Nawaz、2011年

@Chris_vr:auto_ptrのような標準コンテナでは動作しませんstd::vectorstd::listなどがこの参照:stackoverflow.com/questions/111478/...
ナワズ

いいですね。 FILEと行を記述します。operator newあなたが使用しているそれのこれらのバージョンは何であり、何ですか?

14

最初にメモリリークが発生するリスクを最小限に抑えるのに役立つ、よく知られたプログラミング手法がいくつかあります。

  • 独自の動的メモリ割り当てを行う必要がある場合はnewdelete常にペアで書き込み、割り当て/割り当て解除コードがペアで呼び出されるようにします
  • 可能であれば、動的メモリ割り当てを避けてください。たとえば、vector<T> t代わりに可能な限り使用しますT* t = new T[size]
  • ブーストスマートポインターのような「スマートポインター」を使用する(http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm
  • 私の個人的なお気に入り:ポインターの所有権の概念を理解していることを確認し、ポインターを使用するすべての場所で、どのコードエンティティが所有者であるかを確認してください。
  • C ++コンパイラーによって自動的に作成されるコンストラクター/代入演算子、およびポインターを所有するクラスがある場合の意味(または、所有しないオブジェクトへのポインターを含むクラスがある場合の意味)について学習します。

オブジェクトのauto_pointerを使用すると、オブジェクト内の他のクラスオブジェクトポインターがすべて削除されます。
Chris_vr

@Chris_vr:auto_pointerについて特定の質問がある場合は、例を含めて新しい質問をすることをお勧めします。
Doc Brown

多くの投稿で、vector <>はクリア時にメモリが解放されることを保証しないと言っています。私はスワップなどを個人的にテストし、特に動的に使用するとvector <>がリークしているという結論に達しました。'new'とクリーンアップを正しく使用して、日曜大工の動的割り当てよりvector <>にアドバイスする方法がわかりません。私の埋め込みプログラムでは、すべてのリークのため、動的なものにvector <>を使用することを避けています。そこで、私はnewまたはstd :: listを使用します
bart s

文字数が多すぎるため、2つ目のコマンドを入力します。残念ながら私の組み込みC ++、私はベクトルにshrink_to_fitを持っていない古いC ++(?98)を持っているに...しかし組み込まれたプログラムは、必ず完全にベクトル<>動的を使用してメモリ不足時にクラッシュする100%
バートの


8
  1. Windows用デバッグツールをダウンロードします
  2. gflagsユーティリティを使用して、ユーザーモードのスタックトレースをオンにします。
  3. UMDHプログラムのメモリの複数のスナップショットを取得するために使用します。メモリが割り当てられる前にスナップショットを作成し、プログラムがメモリリークを起こしたと思われる時点で2番目のスナップショットを作成します。プログラムに一時停止またはプロンプトを追加してUMDH、スナップショットを実行して取得する機会を与えることができます。
  4. UMDHもう一度実行します。今回は、2つのスナップショットを比較するモードで実行します。次に、メモリリークの疑いのあるコールスタックを含むレポートを生成します。
  5. gflags完了したら、以前の設定を復元します。

UMDHプロセス全体のメモリ割り当てを監視しているため、CRTデバッグヒープよりも多くの情報が得られます。サードパーティのコンポーネントがリークしているかどうかもわかります。


1
私は標準プロファイラーよりもDeleakerとValgrindを好みます
z0r1fan 2018

8

「Valgrind」を実行すると、次のことができます。

1)メモリリークの特定に役立つ - メモリリークの数を示し、リークしたメモリが割り当てられたコードの行を指摘します。

2)メモリを解放しようとする誤った試みを指摘する(例:の不適切な呼び出しdelete

「Valgrind」の使用方法

1)ここで valgrindを取得します

2)-gフラグを使用してコードをコンパイルします

3)シェルを実行します。

valgrind --leak-check=yes myprog arg1 arg2

ここで、「myprog」はコンパイルされたプログラムでarg1arg2はプログラムの引数です。

4)結果は、malloc/ への呼び出しのリストで、new削除を解放するための後続の呼び出しはありませんでした。

例えば:

==4230==    at 0x1B977DD0: malloc (vg_replace_malloc.c:136)

==4230==    by 0x804990F: main (example.c:6)

malloc(解放されなかった)どの行で呼び出されたかを通知します。

他の人が指摘したように、すべてのnew/ malloc呼び出しについて、後続のdelete/ free呼び出しがあることを確認してください。


6

gccを使用している場合は、gprofを利用できます。

プログラマがメモリリークを見つける方法を知りたい

いくつかはツールを使用し、いくつかはあなたが行うことを行い、ピアコードレビューを通じても可能です

プログラムにメモリリークがないことを確認するために従うべき標準または手順はありますか

私にとっては、動的に割り当てられたオブジェクトを作成するときは常に、解放コードを後に配置し、その間にコードを埋めます。コードの間に例外がないことが確実であれば、これは問題ありません。それ以外の場合は、try-finallyを使用します(C ++を頻繁に使用しません)。


コンストラクタに割り当てられたものを削除できないことがあります。
Chris_vr

5
  1. Visual Studioには、Cランタイムライブラリと呼ばれるメモリリークの組み込み検出機能があります。main関数が戻った後にプログラムが終了すると、CRTはアプリケーションのデバッグヒープをチェックします。デバッグヒープにブロックがまだ割り当てられている場合は、メモリリークがあります。

  2. このフォーラムでは、C / C ++でのメモリリークを回避するいくつかの方法について説明します。


5

コードでの出現を検索newし、すべてがコンストラクター内で出現し、デストラクターで一致する削除が行われていることを確認します。これがそのコンストラクターで唯一スローされる可能性のある操作であることを確認してください。これを行う簡単な方法は、すべてのポインタをstd::auto_ptrまたはでラップするboost::scoped_ptrことです(移動のセマンティクスが必要かどうかによって異なります)。今後のすべてのコードでは、すべてのリソースが、デストラクタ内のリソースをクリーンアップするオブジェクトによって所有されていることを確認してください。移動のセマンティクスが必要な場合は、r値参照をサポートするコンパイラーにアップグレードし(VS2010は私が信じている)、移動コンストラクターを作成できます。そうしたくない場合は、スワップの慎重な使用を含むさまざまなトリッキーなテクニックを使用するか、Boost.Moveライブラリを試すことができます。


コンストラクタで割り当てられたメモリを常に削除できるとは限りません。この状況への対処方法
Chris_vr

@Chris_vrどういう意味?すべてのポインターメンバーがscope_ptrsであり、それぞれが個別に初期化されている場合、正常に構築されたメンバーはすべてポインターを削除し、他のメンバーはまだ割り当てられたメモリへのポインターを保持していません。仕事から家に帰った数時間後に例をあげます。
Mankarse

@Chris_vr:特定の例がある場合は、新しい質問として投稿してください。そこで議論できます。
ドクブラウン

5

Valgrindツールを使用して、メモリリークを検出できます。

また、特定の関数のリークを見つけるには、関数の最後でexit(0)を使用し、Valgrindで実行します

`$` valgrind ./your_CPP_program 

5

自動メモリリークチェッカーの調査

この回答では、簡単に理解できるメモリリークの例で、いくつかの異なるメモリリークチェッカーを比較します。

何よりもまず、人に知られているすべてのツールを比較するASan wikiの次の巨大なテーブルを参照してください:https : //github.com/google/sanitizers/wiki/AddressSanitizerComparisonOfMemoryTools/d06210f759fec97066888e5f27c7e722832b0924

分析される例は次のとおりです。

main.c

#include <stdlib.h>

void * my_malloc(size_t n) {
    return malloc(n);
}

void leaky(size_t n, int do_leak) {
    void *p = my_malloc(n);
    if (!do_leak) {
        free(p);
    }
}

int main(void) {
    leaky(0x10, 0);
    leaky(0x10, 1);
    leaky(0x100, 0);
    leaky(0x100, 1);
    leaky(0x1000, 0);
    leaky(0x1000, 1);
}

GitHubアップストリーム

さまざまなツールがどのようにリークのある呼び出しを示しているかを確認します。

Googleのgperftoolsのtcmalloc

https://github.com/gperftools/gperftools

Ubuntu 19.04での使用:

sudo apt-get install google-perftools
gcc -ggdb3 -o main.out main.c -ltcmalloc
PPROF_PATH=/usr/bin/google-pprof \
  HEAPCHECK=normal \
  HEAPPROFILE=ble \
  ./main.out \
;
google-pprof main.out ble.0001.heap --text

プログラム実行の出力には、メモリリーク分析が含まれています。

WARNING: Perftools heap leak checker is active -- Performance may suffer
Starting tracking the heap
Dumping heap profile to ble.0001.heap (Exiting, 4 kB in use)
Have memory regions w/o callers: might report false leaks
Leak check _main_ detected leaks of 272 bytes in 2 objects
The 2 largest leaks:
Using local file ./main.out.
Leak of 256 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581d3 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start
Leak of 16 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581b5 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start


If the preceding stack traces are not enough to find the leaks, try running THIS shell command:

pprof ./main.out "/tmp/main.out.24744._main_-end.heap" --inuse_objects --lines --heapcheck  --edgefraction=1e-10 --nodefraction=1e-10 --gv

If you are still puzzled about why the leaks are there, try rerunning this program with HEAP_CHECK_TEST_POINTER_ALIGNMENT=1 and/or with HEAP_CHECK_MAX_POINTER_OFFSET=-1
If the leak report occurs in a small fraction of runs, try running with TCMALLOC_MAX_FREE_QUEUE_SIZE of few hundred MB or with TCMALLOC_RECLAIM_MEMORY=false, it might help find leaks more re
Exiting with error code (instead of crashing) because of whole-program memory leaks

の出力にgoogle-pprofは、ヒープ使用量分析が含まれています。

Using local file main.out.
Using local file ble.0001.heap.
Total: 0.0 MB
     0.0 100.0% 100.0%      0.0 100.0% my_malloc
     0.0   0.0% 100.0%      0.0 100.0% __libc_start_main
     0.0   0.0% 100.0%      0.0 100.0% _start
     0.0   0.0% 100.0%      0.0 100.0% leaky
     0.0   0.0% 100.0%      0.0 100.0% main

出力は、3つのリークのうち2つを示しています。

Leak of 256 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581d3 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start
Leak of 16 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581b5 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start

3つ目が表示されなかった理由がわかりません

いずれにせよ、通常何かが漏れるとき、それは何度も起こり、実際のプロジェクトでそれを使用したとき、漏れている関数を非常に簡単に指摘されてしまいました。

出力自体で述べたように、これにより実行速度が大幅に低下します。

さらなるドキュメント:

参照:TCMallocの使用方法

Ubuntu 19.04、google-perftools 2.5-2でテスト済み。

GoogleによるAddress Sanitizer(ASan)も

https://github.com/google/sanitizers

以前に言及:C ++コード/プロジェクトでメモリリークを見つける方法?TODO vs tcmalloc。

これはすでにGCCに統合されているので、次のことができます。

gcc -fsanitize=address -ggdb3 -o main.out main.c
./main.out 

および実行出力:

=================================================================
==27223==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 4096 byte(s) in 1 object(s) allocated from:
    #0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
    #1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
    #2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
    #3 0x55bf86c5f210 in main /home/ciro/test/main.c:20
    #4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)

Direct leak of 256 byte(s) in 1 object(s) allocated from:
    #0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
    #1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
    #2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
    #3 0x55bf86c5f1f2 in main /home/ciro/test/main.c:18
    #4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)

Direct leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
    #1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
    #2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
    #3 0x55bf86c5f1d4 in main /home/ciro/test/main.c:16
    #4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)

SUMMARY: AddressSanitizer: 4368 byte(s) leaked in 3 allocation(s).

すべてのリークを明確に識別します。いいね!

牙山はまた、このような範囲外の書き込みなどの他のクールなチェックを行うことができますスタックが検出スマッシング

Ubuntu 19.04、GCC 8.3.0でテスト済み。

ヴァルグリンド

http://www.valgrind.org/

以前に言及:https : //stackoverflow.com/a/37661630/895245

使用法:

sudo apt-get install valgrind
gcc -ggdb3 -o main.out main.c
valgrind --leak-check=yes ./main.out

出力:

==32178== Memcheck, a memory error detector
==32178== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==32178== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==32178== Command: ./main.out
==32178== 
==32178== 
==32178== HEAP SUMMARY:
==32178==     in use at exit: 4,368 bytes in 3 blocks
==32178==   total heap usage: 6 allocs, 3 frees, 8,736 bytes allocated
==32178== 
==32178== 16 bytes in 1 blocks are definitely lost in loss record 1 of 3
==32178==    at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178==    by 0x10915C: my_malloc (main.c:4)
==32178==    by 0x109179: leaky (main.c:8)
==32178==    by 0x1091B4: main (main.c:16)
==32178== 
==32178== 256 bytes in 1 blocks are definitely lost in loss record 2 of 3
==32178==    at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178==    by 0x10915C: my_malloc (main.c:4)
==32178==    by 0x109179: leaky (main.c:8)
==32178==    by 0x1091D2: main (main.c:18)
==32178== 
==32178== 4,096 bytes in 1 blocks are definitely lost in loss record 3 of 3
==32178==    at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178==    by 0x10915C: my_malloc (main.c:4)
==32178==    by 0x109179: leaky (main.c:8)
==32178==    by 0x1091F0: main (main.c:20)
==32178== 
==32178== LEAK SUMMARY:
==32178==    definitely lost: 4,368 bytes in 3 blocks
==32178==    indirectly lost: 0 bytes in 0 blocks
==32178==      possibly lost: 0 bytes in 0 blocks
==32178==    still reachable: 0 bytes in 0 blocks
==32178==         suppressed: 0 bytes in 0 blocks
==32178== 
==32178== For counts of detected and suppressed errors, rerun with: -v
==32178== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)

したがって、もう一度、すべてのリークが検出されました。

参照:valgrindを使用してメモリリークを見つけるにはどうすればよいですか?

Ubuntu 19.04、valgrind 3.14.0でテスト済み。


4

Visual Leak Detector(VLD)は、Visual C ++用の無料で堅牢なオープンソースのメモリリーク検出システムです。

Visual Studioデバッガーでプログラムを実行すると、Visual Leak Detectorはデバッグセッションの最後にメモリリークレポートを出力します。リークレポートには、リークされたメモリブロックがどのように割り当てられたかを示す完全なコールスタックが含まれます。コールスタックの行をダブルクリックして、エディタウィンドウでそのファイルと行にジャンプします。

クラッシュダンプしかない場合は、Windbg !heap -lコマンドを使用できます。リークされたヒープブロックが検出されます。gflagsオプションを開くと、「ユーザーモードスタックトレースデータベースの作成」を開くと、メモリ割り当て呼び出しスタックが表示されます。


4

MTunerは、MSVC、GCC、およびClangコンパイラをサポートする無料のマルチプラットフォームメモリプロファイリング、リーク検出および分析ツールです。機能は次のとおりです。

  • メモリ使用量とライブメモリブロックの履歴に基づくタイムライン
  • ヒープ、メモリタグ、時間範囲などに基づく強力なメモリ操作フィルタリング
  • 完全なソースコードを使用した手動インストルメンテーション用SDK
  • コマンドラインの使用による継続的な統合のサポート
  • 呼び出しスタックツリーとツリーマップナビゲーション
  • はるかに。

ユーザーは、GCCまたはClangクロスコンパイラを使用して、プラットフォームをターゲットとするソフトウェアをプロファイルできます。MTunerには、Windows、PlayStation 4、PlayStation 3プラットフォームのサポートが組み込まれています。


これは受け入れられる答えになるはずです。これは優れたツールであり、他の人ができない量の割り当て/割り当て解除を処理できます。
セルジュ・ロガッチ

3

Windowsでは、CRTデバッグヒープを使用できます

プログラムにメモリリークがないことを確認するために従うべき標準または手順はありますか?

ええ、手動のメモリ管理は使用しないでください(電話をかけdeleteたりdelete[]手動で行ったりした場合は、間違っています)。RAIIとスマートポインターを使用して、ヒープ割り当てを絶対最小値に制限します(ほとんどの場合、自動変数で十分です)。


3

質問の2番目の部分に答えて、

プログラムにメモリリークがないことを確認するために従うべき標準または手順はありますか?

はいあります。これは、CとC ++の主な違いの1つです。

C ++では、ユーザーコードを呼び出しnewたりdelete、呼び出したりすることはできません。RAIIは非常に一般的に使用される手法であり、リソース管理の問題をほぼ解決します。プログラム内のすべてのリソース(リソースとは、取得して後で解放する必要があるもののことです。ファイルハンドル、ネットワークソケット、データベース接続だけでなく、単純なメモリ割り当てもあり、API呼び出しのペア(BeginX( )/ EndX()、LockY()、UnlockY())はクラスでラップする必要があります。

  • コンストラクタリソースを取得します(newリソースがメモリ割り当てである場合にます)
  • デストラクタリソースを解放し、
  • コピーと割り当ては(コピーコンストラクターと割り当て演算子をプライベートにすることによって)防止されるか、または正しく機能するように実装されます(たとえば、基になるリソースを複製することによって)。

次に、このクラスは、ポインターを呼び出して格納することによってではなく、スタック上で、またはクラスメンバーとしてローカルにインスタンス化されnewます。

多くの場合、これらのクラスを自分で定義する必要はありません。標準ライブラリコンテナもこのように動作するため、a std::vectorに格納されているオブジェクトは、ベクターが破棄されると解放されます。繰り返しになりますが、コンテナにポインタを格納しないでください(and を呼び出す必要があります)ではなく、オブジェクト自体(メモリ管理を無料で提供します)。同様に、スマートポインタクラスを使用して、次のように割り当てる必要があるオブジェクトを簡単にラップできます。newdeletenew、その寿命を制御できます。

つまり、オブジェクトがスコープ外になると、オブジェクトは自動的に破棄され、リソースが解放されてクリーンアップされます。

コード全体でこれを一貫して行うと、メモリリークが発生しなくなります。リークされる可能性のあるすべてのもの、オブジェクトが宣言されたスコープをコントロールが離れると呼び出されることが保証されているデストラクタに関連付けられています。


スマートポインターがクラスを保持し、そのクラスに他のいくつかのクラスのポインターが含まれている場合。スマートがオフになると、内部のすべてのポインターが安全に削除されます。
Chris_vr

@Chris:スマートポインターによってポイントされているオブジェクトに、必要なクリーンアップを実行するデストラクターがあるまたはオブジェクトに、必要なクリーンアップを実行するためのデストラクターを持っているメンバーが含まれていると想定します。本質的に、すべてのオブジェクトがそれ自体を処理する(破棄されたときに自動的にクリーンアップされる)限り、すべてのオブジェクトがポインタとしてではなく、値によって格納される限り、解放する必要があるすべてが解放れます。
jalf

3

AddressSanitizer(ASan)は、高速メモリエラー検出器です。C / C ++プログラムの解放後使用および{ヒープ、スタック、グローバル}バッファーオーバーフローのバグを検出します。それは見つけます:

  • 解放後使用(ダングリングポインター逆参照)
  • ヒープバッファオーバーフロー
  • スタックバッファオーバーフロー
  • グローバルバッファオーバーフロー
  • 返却後の使用
  • 初期化注文のバグ

このツールは非常に高速です。インストルメントされたプログラムの平均的なスローダウンは、約2倍です。



0

他の回答で提供されているツールとメソッドに加えて、静的コード分析ツールを使用して、メモリリーク(およびその他の問題)を検出できます。Cppcheckは無料の堅牢なツールです。しかし、他にもたくさんのツールがあります。ウィキペディアには、静的コード分析ツールのリストがあります。


-1

すべてのヒープメモリが正常に解放されていることを確認してください。ヒープにメモリを割り当てない場合は必要ありません。その場合は、メモリをmallocする回数をカウントし、メモリを解放する回数をカウントアップします。


-3

「新規」または「削除」のどちらもアプリケーションコードで使用しないでください。代わりに、マネージャー/ワーカーイディオムを使用する新しいタイプを作成します。マネージャークラスは、メモリを割り当てて解放し、他のすべての操作をワーカーオブジェクトに転送します。

残念ながら、C ++には "operator。"のオーバーロードがないため、これは必要以上の作業です。ポリモーフィズムがあると、それはさらに多くの作業になります。

しかし、メモリリークについて心配する必要がないため、これは努力する価値があります。つまり、メモリリークを探す必要すらないということです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.