(アンマネージ)コードのメモリリークをどのように検出/回避しますか?[閉まっている]


125

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

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

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

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


リークの回避に関しては、次の投稿にいくつかのアドバイスがあります。http
//stackoverflow.com/questions/27492/c-memory-management


これをビジュアルスタジオで使用して、メモリリークを検出しました。codeproject.com/KB/applications/visualleakdetector.aspx
tiboo

1
あなたはsirh valgrin(Linuxの場合)またはdeleaker(Windowsの場合)、視覚的な漏れ検出器も見てください...
John Smith

メモリリークを見つけるためにここをチェック:theunixshell.blogspot.com/2013/11/...
ビジェイ

回答:


78

C / C ++コードを* nixに移植できる場合、Valgrindよりも優れた点はいくつかあります。


1
ValgrindはOS Xでも動作するようになったため、Linuxが唯一の選択肢ではありません。
マイケルアンダーソン、

1
Linux(およびOS X)用のValgrind。あなたがwindoseを使用する場合-deleaker-すべての中で最高!
ジョン・スミス

@JordiBunster:いいね!しかしランタイムベース。大きなコードベース(場合によってはCで記述)を使用して、主にプログラムの設計方法をテストします。攻撃者は、メモリリークの悪用を見つけるために、コードの読み取りに数千時間かかる可能性があります。JavaScriptに存在するものと同様のソースコード分析用の自動化ツールを期待していました。
user2284570

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リンクで説明されている他の手法も使用できます。


この方法に関するメモ:これは、mallocおよびfreeで純粋なCを使用している場合にのみ機能するようです。C ++の新規および削除を使用している場合、行番号を含む詳細レポートは作成されません。
Zach

2
@Zach:実際にこれを機能させることもできます(実際に自分でコンパイルしたコードの場合)-social.msdn.microsoft.com/forums/en-US/vcgeneral/thread/…で
Roman Starkov

これはリリースモードでも機能しますか?
JV 2015

1
@ user3152463いいえ。ドキュメントによると、デバッグビルドでのみ機能します:msdn.microsoft.com/en-us/library/e5ewb1h3(
Dusty Campbell

この行は間違っています:#define CRTDBG_MAP_ALLOC次のようになります:#define _CRTDBG_MAP_ALLOC
Fallso

37

C ++の場合:RAIIを使用します。以下のようなスマートポインタはstd::unique_ptrstd::shared_ptrstd::weak_ptrあなたの友人です。


1
std:vectorは、配列(バッファ)が割り当てられているのと同じ関数で割り当て解除された場合の優れた代替品です。
KJAWolf 2008

4
少なくともstd :: auto_ptrとboost :: shared_ptrは依然としてリークの影響を受けやすい。
Jasper Bekkers、2008

5
それらを誤って使用した場合にのみ、std :: auto_ptrを誤って使用することは簡単です。
Leon Timmermans、

2
これはコーディング標準の良いアドバイスですが、質問には答えません。shared_ptrを使用しても、循環依存関係のあるリークが発生する可能性があります。そして、ガベージコレクションされた言語にも適用される、無制限のキャッシュ戦略で「リーク」を起こすことができます。
CashCow 2016年

@CashCow:あなたは正しいです。実際にはまだ見ていませんが、多用しているためでしょう。以下の答えを引用するには、「絶対に必要な場合にのみポインタを使用してください」。
Leon Timmermans

28

C ++開発者としてのガイドラインは次のとおりです。

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

個人的にメモリリークの検出については、常にVisual Leak Detectorを使用しており、非常に便利であることがわかりました。


2
Visual Leak Detectoreが新しいサイトvld.codeplex.comに移動
KindDragon

VLDは本当に素晴らしいリーク検出器です
-VC

1
ポイント#1の+1。これは絶対に基本的なことです。残念ながら、いくつかの最大の「C ++」ライブラリーは、多くの場合識別可能な理由なしに、スタック割り当てやRAIIを避け、Pointers Everywhereを優先する傾向があるように見えます。したがって、実際にはC ++ではなく「クラス付きC」になります。
underscore_d

16

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

ヒープ割り当て要求の追跡 -特に、一意の割り当て要求番号に関するセクション

_CrtSetDbgFlag

_CrtSetBreakAlloc

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


10

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


3
リンクが機能しなくなった場合は、ドキュメント(support.microsoft.com/kb/2580960)とダウンロード(microsoft.com/en-us/download/details.aspx?id=26798
JPaget

7

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


1
このツールは本当に完璧です!_CrtDumpMemoryLeaks();を使用する手間を省きます。MSDNで説明されているように。1つのインクルードだけですべてが公開されます!古いCライブラリでも動作します!
m_pGladiator 2010

(VS2013用)の新しいバージョンはここにある:vld.codeplex.com
Dženan

7

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

あなたがC ++を使用している場合、あなたは常に新しい明示的に使用を避けることができます:あなたが持っていますvectorstringauto_ptr(事前C ++ 11;に置き換えunique_ptr11 ++ Cで)、unique_ptr(C ++ 11)及びshared_ptr(C ++ 11)あなたの武器インチ

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


1
そして、3または5のルールを忘れないでください
フマムヘルファウィ

4

最後に関数を呼び出せるようにするさまざまな置換「malloc」ライブラリがあり、すべての未解放のメモリ、および多くの場合、最初にそれをmalloc(またはnew'd)したユーザーについて通知します。


4

MS VC ++を使用している場合は、codechenのこの無料ツールを強くお勧めします: Jochen Kalmbachによるleakfinder

クラスをプロジェクトに追加し、

InitAllocCheck(ACOutput_XML)
DeInitAllocCheck()

リークをチェックするコードの前後。

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

Rationalの(現在はIBMが所有している)PurifyPlusは、同様の方法でリークを示していますが、leakfinderツールは実際にはより使いやすく、そのメリットは数千ドルもかからないことです!


1
私はリークファインダーをチェックアウトしましたが、問題はありませんが、インラインアセンブリが含まれているため、x64の場合はそのままでは機能しません。
Zach


3

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


2

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

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

他の人が持っているものの、私は助けを提供するためにUNIX側について十分に知りません。

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


2

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

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

  2. それは少しくだらないですが、私はそれが私を当惑させることはありません。

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

それを使用するときに注意しなければならないことがいくつかあります:頼りにする必要があることは何もしないでください new基礎となるコードに頼るでください。イメージダンプを実行するコードで(および問題を修正すると)、巨大なファイルが生成される場合があります。

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

繰り返しますが、私はしばらくこれを使用していないので、少し作業する必要があるかもしれません。アイデアを説明するためにそれをドロップします。十分な関心があることが判明した場合は、サンプルを作成してプロセスのコードを更新し、次のURLのコンテンツを、きちんとした構文の色のリストを含むより良いものに置き換えます。

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


2

Linuxの場合:Google Perftoolsをお試しください

Goolge Perftoolsの長所である、同様のalloc / freeカウントを行うツールはたくさんあります。

  • かなり速い(valgrindと比較して:非常に速い)
  • 結果の素晴らしいグラフィック表示が付属しています
  • 他の便利な機能があります:CPUプロファイリング、メモリ使用量プロファイリング...


2

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

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


2

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

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


Memory Validatorは、ネイティブコードを呼び出すC#のファイル名と行番号も提供します。x64バージョンはベータ版です
Stephen Kellett

2

呼び出しを記録し、実際の関数に呼び出しを渡す独自のsyscall関数を補間することにより、割り当てと解放をカウントしていますか?

これは、記述していないコードからの呼び出しを追跡できる唯一の方法です。

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

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


1

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


1

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


1

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

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

1

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

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

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


1

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

実動システムが今リークしていることに気づき、テストでそれを再現する方法がわからない場合はどうでしょうか。何が問題なのかという証拠は、その運用システムの状態で取得されます。問題を再現するには、問題の場所に関する洞察を提供するだけで十分な場合があります。

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

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


1

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


スプリントはlintのより新しい代替品です。
Mark Kegel、

@ user14788:GimpelのPC-Lint製品は、古いUnixよりもはるかにモダンですlint。これには、C ++に固有の多くのチェックがありますが、afaikスプリントにはありません。回答のリンク(LintからPC-Lintに名前を変更しました)を参照してください。
Dan

0

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


0

検出:

CRTのデバッグ

避ける:

スマートポインター、boehm GC


0

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

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


0

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


スローダウンによって結果が役に立たなくなる理由はわかりません。リークされたメモリは、プログラムの実行速度に関係なく確実にリークされます。これらのツールの目的はリークを見つけることです。それで問題はどこにあるのでしょうか?実行速度が非常に遅いため、プロファイルするためにすべてのコードパスを物理的にカバーすることができませんでしたか?
underscore_d

-1

MtraceはLinuxに標準で組み込まれているようです。手順は次のとおりです。

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

  6. mtrace your_prog_exe_name /tmp/mtrace.datを使用してリーク情報を表示します
    (私はyum install glibc_utilsを使用して最初にmora perlスクリプトをfedoraシステムにインストールする必要がありました   )

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