125

アンマネージ C/C++ コードで、メモリ リークを検出するためのベスト プラクティスは何ですか? 避けるべきコーディングガイドラインは?(あたかもそれがとても単純であるかのように;)

過去に少しばかげた方法を使用しました: メモリ割り当て呼び出しごとにカウンターをインクリメントし、解放中にデクリメントします。プログラムの最後に、カウンター値はゼロになるはずです。

私はこれが素晴らしい方法ではなく、いくつかの問題があることを知っています. (たとえば、プラットフォーム API 呼び出しによって割り当てられたメモリを解放する場合、割り当てカウントは解放カウントと正確には一致しません。もちろん、メモリを割り当てた API 呼び出しを呼び出すときにカウンターをインクリメントしました。)

あなたの経験、提案、そしておそらくこれを簡素化するツールへの参照を期待しています。

4

29 に答える 29

79

C/C++ コードが *nix に移植可能である場合、Valgrindより優れているものはほとんどありません。

于 2008-09-05T12:22:55.193 に答える
65

Visual Studio を使用している場合、Microsoft は、メモリ リークを検出してデバッグするための便利な機能をいくつか提供しています。

この記事から始めます: https://msdn.microsoft.com/en-us/library/x98tx3cf(v=vs.140).aspx

これらの記事の簡単な要約を次に示します。まず、次のヘッダーを含めます。

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

次に、プログラムが終了するときにこれを呼び出す必要があります。

_CrtDumpMemoryLeaks();

または、プログラムが毎回同じ場所で終了しない場合は、プログラムの開始時にこれを呼び出すことができます。

_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

プログラムが終了すると、解放されなかったすべての割り当てが、割り当てられたファイルと割り当ての発生とともに出力ウィンドウに出力されます。

この戦略は、ほとんどのプログラムで機能します。ただし、場合によってはそれが困難または不可能になります。起動時に何らかの初期化を行うサードパーティ ライブラリを使用すると、他のオブジェクトがメモリ ダンプに表示され、リークの追跡が困難になる可能性があります。また、いずれかのクラスにメモリ割り当てルーチン ( malloc など) と同じ名前のメンバーがある場合、CRT デバッグ マクロは問題を引き起こします。

上記の MSDN リンクで説明されている他の手法も使用できます。

于 2008-09-08T16:30:57.587 に答える
36

C++ の場合: RAII を使用します。std::unique_ptrstd::shared_ptr、 のような賢いポインタstd::weak_ptrはあなたの友達です。

于 2008-09-05T14:38:15.667 に答える
28

C++ 開発者として、簡単なガイドラインをいくつか示します。

  1. 絶対に必要な場合にのみポインターを使用する
  2. ポインターが必要な場合は、SmartPointerが可能かどうかを再確認してください
  3. GRASP Creatorパターンを使用します。

個人的にメモリ リークの検出に関しては、私は常にVisual Leak Detectorを使用しており、非常に便利だと感じています。

于 2008-09-05T12:26:42.737 に答える
16

私はもう何年もの間 DevStudio を使用してきましたが、デバッグ ランタイム ライブラリで利用できるメモリ分析ツールについて知らないプログラマがいかに多いかにいつも驚かされます。開始するためのいくつかのリンクを次に示します。

ヒープ割り当てリクエストの追跡- 具体的には、一意の割り当てリクエスト番号に関するセクション

_CrtSetDbgFlag

_CrtSetBreakAlloc

もちろん、DevStudio を使用していない場合、これは特に役に立ちません。

于 2008-09-05T12:55:54.227 に答える
10

Windows OS のDebugDiagについて誰も言及していないことに驚いています。
リリース ビルドだけでなく、顧客のサイトでも機能します。
(リリース バージョンの PDB を保持し、Microsoft パブリック シンボル サーバーを使用するように DebugDiag を構成するだけで済みます)

于 2008-10-12T11:37:29.043 に答える
7

デバッグ モードの Microsoft VC++ ではメモリ リークが表示されますが、リークの場所は表示されません。

C++ を使用している場合は、常に new を明示的に使用することを避けることができます: vector, string, auto_ptr(pre C++11; C++11 では に置き換えられましunique_ptrた), unique_ptr(C++11) およびshared_ptr(C++11) が武器庫にあります。

new が避けられない場合は、コンストラクターで非表示にするようにしてください (およびデストラクタで削除を非表示にします)。サードパーティの API でも同じことができます。

于 2008-09-05T12:28:12.857 に答える
7

Visual Leak Detector は非常に優れたツールですが、VC9 ランタイム (MSVCR90D.DLL など) の呼び出しはサポートしていません。

于 2008-12-22T23:19:33.600 に答える
4

最後に関数を呼び出すことができるさまざまな代替「malloc」ライブラリがあり、解放されていないすべてのメモリと、多くの場合、最初にそれを malloc (または new) したのは誰かを教えてくれます。 .

于 2008-09-05T12:22:51.233 に答える
4

MS VC++ を使用している場合は、codeproject のこの無料ツールを強くお勧めし ます

クラスをプロジェクトに追加するだけで、

InitAllocCheck(ACOutput_XML)
DeInitAllocCheck()

リークをチェックしたいコードの前後。

コードをビルドして実行すると、Jochen は適切な GUI ツールを提供します。このツールでは、結果の .xmlleaks ファイルをロードし、各リークが生成されたコール スタックをナビゲートして問題のあるコード行を突き止めます。

Rational (現在は IBM が所有) の PurifyPlus は同様の方法でリークを示していますが、数千ドルもかからず、実際にはリークファインダー ツールの方が使いやすいことがわかりました。

于 2008-09-05T12:54:00.347 に答える
3

自分で使ったことはありませんが、C の友達がPurifyと教えてくれます。

于 2008-09-05T12:22:31.000 に答える
3

Visual Studio を使用している場合は、Bounds Checkerを見る価値があるかもしれません。無料ではありませんが、コードのリークを見つけるのに非常に役立ちました。メモリ リークだけでなく、GDI リソース リーク、WinAPI 使用エラーなども発生します。リークしたメモリが初期化された場所も表示されるため、リークの追跡がはるかに簡単になります。

于 2008-09-05T12:50:16.580 に答える
2

リークに対する最善の防御策は、mallocの使用を最小限に抑えるプログラム構造です。これは、プログラミングの観点から優れているだけでなく、パフォーマンスと保守性も向上させます。私はmallocの代わりに他のものを使用することについて話しているのではなく、オブジェクトを再利用し、ガベージコレクターを使用する言語でよく使用されるようなウィリーニリーを割り当てるのではなく、渡されるすべてのオブジェクトに非常に明示的なタブを維持するという点でJavaのように。

たとえば、私が取り組んでいるプログラムには、画像データを表す一連のフレームオブジェクトがあります。各フレームオブジェクトには、フレームのデストラクタが解放するサブデータがあります。プログラムは、割り当てられたすべてのフレームのリストを保持し、新しいフレームが必要な場合は、未使用のフレームオブジェクトのリストをチェックして、新しいフレームを割り当てるのではなく、既存のフレームを再利用できるかどうかを確認します。シャットダウン時には、リストを繰り返し処理して、すべてを解放します。

于 2008-09-16T08:22:26.273 に答える
2

この質問に対する簡単な答えはないと思います。このソリューションに実際にどのようにアプローチするかは、要件によって異なります。クロスプラットフォームソリューションが必要ですか?new/deleteまたはmalloc/free(あるいはその両方)を使用していますか?本当に「リーク」だけを探しているのですか、それともバッファオーバーラン(またはアンダーラン)の検出など、より優れた保護が必要ですか?

Windows側で作業している場合、MSデバッグランタイムライブラリにはいくつかの基本的なデバッグ検出機能があり、別のライブラリがすでに指摘しているように、リーク検出に役立ついくつかのラッパーをソースに含めることができます。new/deleteとmalloc/freeの両方で機能するパッケージを見つけると、明らかに柔軟性が高まります。

私はUNIX側について十分な知識がありませんが、他の人は助けを提供しています。

ただし、リーク検出だけでなく、バ​​ッファオーバーラン(またはアンダーラン)を介してメモリの破損を検出するという概念もあります。このタイプのデバッグ機能は、単純なリーク検出よりも難しいと思います。このタイプのシステムは、C ++オブジェクトを使用している場合にもさらに複雑になります。これは、polymorhpicクラスをさまざまな方法で削除できるため、削除される真のベースポインターを判別するのが難しいためです。私は、オーバーランに対して適切な保護を行う優れた「無料」システムを知りません。システム(クロスプラットフォーム)を作成しましたが、かなり難しいことがわかりました。

于 2008-09-05T14:49:18.603 に答える
2

過去に時々使用したものを提供したいと思います。ソースレベルでかなり自動化された基本的なリークチェッカーです。私は3つの理由でこれを配っています:

  1. あなたはそれが役に立つと思うかもしれません。

  2. それは少し厄介ですが、私はそれが私を当惑させません。

  3. いくつかのwin32フックに関連付けられていますが、それは簡単に軽減できるはずです。

使用する際には注意が必要なことがあります。基礎となるコードに頼る必要のあることは何もしないnewでください。leakcheck.cppの先頭で見逃す可能性のあるケースに関する警告に注意してください。画像ダンプを行うコードで(そして問題を修正して)、巨大なファイルを生成する可能性があります。

この設計は、ヘッダーを含むすべてを再コンパイルすることなく、チェッカーのオンとオフを切り替えることができるようにすることを目的としています。チェックを追跡して再構築する場所にleakcheck.hを含めます。その後、LEAKCHECK #define'dを使用して、または使用せずに、leakcheck.cppをコンパイルしてから、再リンクしてオンとオフを切り替えます。unleakcheck.hを含めると、ファイル内でローカルでオフになります。2つのマクロが提供されています。CLEARALLOCINFO()は、leakcheck.hを含まない割り当てコードをトラバースするときに、同じファイルと行を不適切に報告することを回避します。ALLOCFENCE()は、割り当てを行わずに、生成されたレポートに1行だけドロップします。

繰り返しになりますが、私はこれをしばらく使用していないので、少し作業する必要があるかもしれないことを理解してください。アイデアを説明するためにドロップします。十分な関心があることが判明した場合は、例を作成し、その過程でコードを更新し、次のURLの内容を適切な構文色のリストを含むより良いものに置き換えたいと思います。

あなたはここでそれを見つけることができます: http ://www.cse.ucsd.edu/~tkammeye/leakcheck.html

于 2008-09-05T17:31:04.143 に答える
2

Linux の場合: Google Perftools を試す

Goolge Perftools の利点である、同様の alloc/free カウントを行うツールが多数あります。

  • 非常に高速 (valgrind と比較して: 非常に高速)
  • 結果の素敵なグラフィカル表示が付属しています
  • 他にも便利な機能があります: cpu-profiling、memory-usage profiling...
于 2008-09-16T08:15:39.003 に答える
2

呼び出しを記録し、呼び出しを実際の関数に渡す独自のシステムコール関数を補間して、割り当てと解放をカウントしていますか?

これは、作成していないコードから発信された呼び出しを追跡できる唯一の方法です。

ld.so の man ページを見てください。または、一部のシステムでは ld.so.1 です。

また、Google LD_PRELOAD を実行すると、www.itworld.com でテクニックを説明する興味深い記事を見つけることができます。

于 2008-09-05T12:24:02.867 に答える
2

ソフトウェア検証からメモリバリデーターを使用することをお勧めします。このツールは、メモリ リークを追跡し、作業中のアプリケーションのメモリ管理を改善するのに非常に役立ちます。

非常に完全で高速なツールです。

于 2008-09-21T12:59:27.257 に答える
1

Motorola の携帯電話のオペレーティング システムで作業する際に、メモリ割り当てライブラリをハイジャックして、すべてのメモリ割り当てを監視しました。メモリ割り当てに関する多くの問題を見つけるのに役立ちました。予防は治療よりも優れているため、 KlockworkPC-Lintなどの静的解析ツールを使用することをお勧めします。

于 2008-09-05T12:23:44.007 に答える
1

少なくとも MS VC++ の場合、C ランタイム ライブラリには、過去に役立つとわかった関数がいくつかあります。関数については、MSDN ヘルプを確認してください_Crt*

于 2008-09-05T13:12:12.127 に答える
1

メモリ デバッグ ツールは金の価値がありますが、何年にもわたって、ほとんどのメモリ/リソース リークがコード化されるのを防ぐために 2 つの簡単なアイデアを使用できることがわかりました。

  1. 割り当てたいリソースの取得コードを書いたら、すぐに解除コードを書いてください。この方法を使用すると、「忘れる」のが難しくなり、ある意味で、余談ではなく、事前に使用されるリソースのライフサイクルについて真剣に考える必要があります。

  2. return はできるだけ控えめに使用してください。割り当てられたものは、可能であれば 1 つの場所でのみ解放する必要があります。リソースの取得とリリースの間の条件付きパスは、できるだけ単純かつ明確になるように設計する必要があります。

于 2009-06-16T03:58:20.683 に答える
1

一般的なコーディングのガイドライン:

  • リソースは、それらが割り当てられているのと同じ「レイヤー」(関数/クラス/ライブラリ) で割り当てを解除する必要があります。
  • これが不可能な場合は、自動割り当て解除を使用してみてください (共有ポインターのブースト...)
于 2008-09-16T08:17:48.437 に答える
1

Paul Nettle の mmgrは、私の長年のお気に入りツールです。ソース ファイルに mmgr.h をインクルードし、TEST_MEMORY を定義すると、アプリの実行中に発生したメモリの問題でいっぱいのテキスト ファイルが配信されます。

于 2008-09-13T23:37:31.013 に答える
1

このリストの一番上 (私が読んだとき) は valgrind でした。テストシステムでリークを再現できる場合、Valgrind は優れています。私はそれを使って大成功を収めました。

本番システムでリークが発生していることに気付いたばかりで、テストでそれを再現する方法がわからない場合はどうすればよいでしょうか? 問題の証拠の一部は、その運用システムの状態でキャプチャされます。問題を再現できるように、問題がどこにあるかについての洞察を提供するのに十分な場合があります。

そこで、モンテカルロ サンプリングの出番です。Raymond Chen のブログ記事「メモリ リークを特定する貧乏人の方法」を読んでから、私の実装を確認してください (Linux を想定し、x86 および x86-64 でのみテスト済み)。

http://github.com/tialaramex/leakdice/tree/master

于 2009-06-20T08:59:46.997 に答える
0

探知:

CRT のデバッグ

避ける:

スマート ポインタ、ベーム GC

于 2008-09-06T09:35:46.930 に答える
0

Valgrind は Linux の優れたオプションです。MacOS X では、メモリ割り当ての問題をデバッグするためのいくつかのオプションを備えた MallocDebug ライブラリを有効にできます (malloc のマンページを参照してください。関連する詳細については、「環境」セクションを参照してください)。OS X SDK には、MallocDebug というツールも含まれています (通常は /Developer/Applications/Performance Tools/ にインストールされます)。これは、使用状況とリークを監視するのに役立ちます。

于 2008-09-05T14:42:50.850 に答える
0

malloc、calloc、および reallloc の優れた代替品は rmdebug です。使い方は非常に簡単です。valgrind よりもはるかに高速であるため、コードを広範囲にテストできます。もちろん、いくつかの欠点があります。リークを見つけたら、valgrind を使用してリークが発生した場所を見つける必要があり、malloc を直接テストすることしかできません。間違った使い方をしたために lib がリークした場合、rmdebug はそれを見つけられません。

http://www.hexco.de/rmdebug/

于 2008-10-12T12:17:38.620 に答える
0

ほとんどのメモリ プロファイラーは、大規模で複雑な Windows アプリケーションの速度を低下させ、結果が役に立たなくなるほどにします。私のアプリケーションでリークを見つけるのに適したツールが 1 つあります: UMDH - http://msdn.microsoft.com/en-us/library/ff560206%28VS.85%29.aspx

于 2010-12-02T22:48:41.283 に答える
-1

Mtraceは、Linux用の標準の組み込みのもののようです。手順は次のとおりです。

  1. bashに環境変数MALLOC_TRACEを設定します
    。MALLOC_TRACE=/tmp/mtrace.datexport
    MALLOC_TRACE;
  2. メインソースファイルの先頭に#include<mcheck.h>を追加します
  3. mtrace();を追加します。mainおよびmuntrace()の開始時。下部(returnステートメントの前)
  4. デバッグ情報については、-gスイッチを使用してプログラムをコンパイルしてください
  5. プログラムを実行する

  6. mtrace your_prog_exe_name /tmp/mtrace.datを使用してリーク情報を表示します
    (yum installglibc_utilsを使用して最初にmtraceperlスクリプトをfedoraシステムにインストールする必要がありました  )
于 2009-06-16T03:08:01.560 に答える