web-dev-qa-db-ja.com

Microsoft crtdbg.hと同等のGCCメモリリーク検出?

VisualStudioでMicrosoftMSVCコンパイラを使用して汎用C++ライブラリに長年取り組んだ後、現在Linux/Mac OS Xに移植しています(私たちのために祈ってください)。私はMSVCの単純なメモリリーク検出メカニズムに慣れており、非常に気に入っています。

#ifdef DEBUG
    #define _CRTDBG_MAP_ALLOC
    #define NEW   new( _NORMAL_BLOCK, __FILE__, __LINE__)
    #include <stdlib.h>
    #include <crtdbg.h>
#else
    #define NEW   new
#endif

すべてのメモリ割り当ては、この新しいマクロを使用して行われます。ライブラリを使用するプロセスが終了するたびに、メモリリーク(割り当て解除されていないブロック)が、メモリが最初に割り当てられたファイルと行番号とともにコンソールに報告されます。

私が気に入っているのは、積極的に「パフォーマンスツールを使用して実行」する必要がないこと、またはリークを探していることを示す必要がないことです。プロセスが終了するたびに、通常の開発過程でリークが報告されます。

GCCの世界に移行している今、メモリリーク検出ツールの多くは非常に洗練されているため、リークハンティングモードであることを明示的に示す必要があることがわかりました。私のIDEはXcodeであり、割り当て/リーク検出ツール(InstrumentsやMallocDebugなど)のいくつかを調べましたが、それらを完全に理解するために時間を費やしていないことを認めますそれでも、自動的に警告されるのではなく、事前にリークを探していることを実際に指定する必要があるという事実に、私は延期され続けています。

Xcode 3.2を使用していて、静的分析ツールとの統合がうまく行われていると聞きましたが、これについてはまだ調べていません。私は自分の選択肢が何であるかについてのいくつかのアイデアを探しています。 GCCやXcodeに同等のメカニズムが組み込まれていますか?私が知っていて大好きな非常に基本的な機能を実行する単純なサードパーティのライブラリまたはツールはありますか?それとも私はそれを吸い上げて、物事を行うための新しい方法を学ぶべきですか?

25
Gene Goykhman

" Cross-Platform Memory Leak Detector "を見てください。これは、crtdbg.hの手法と非常によく似ています。

15
Cristian Adam

利用できるオプションがいくつかあります。

まず、最も一般的には、 Valgrind などのツールでアプリケーションを実行できます。これは、NULLポインターの読み取りと書き込み、メモリリークなど、多くのメモリの乱用を示しているはずです。 Valgrindスイートには多数のツールが用意されているので、ぜひチェックしてください。

次に、 LD_PRELOAD トリックを使用するライブラリをいつでも使用できます。基本的に、LD_PRELOADトリックではDLLインジェクションが可能です。つまり、何も変更せずにアプリケーション内のメモリ使用量を追跡するためのツールを作成できます。 dmalloc)などのツールがあります。 および efence それらが提供するデバッグ機能で非常に広範囲に及ぶこと。

最後に、最近のGCCリリースには Mudflap というツールが含まれていました。これは基本的に、関数インストルメンテーションを使用して、dmalloc、efence、およびValgrindと同じメモリ関数の周りに呼び出しをラップします。プログラムは著しく遅くなり、実行時に調整できますが、それでも多くの可能性があるように見えます。

私は3つすべてを使用しましたが、Valgrindが非常に役立つことがわかりました。まだできていませんが、Mudflapの使用にも非常に興味があります。

19
s1n

MALLOC_CHECK_環境変数が役立つ場合もあります。

Malloc(3)のマニュアルページから:

Linux libc(5.4.23以降)およびglibc(2.x)の最近のバージョンには、環境変数を介して調整可能なmalloc()実装が含まれています。 MALLOC_CHECK_が設定されている場合、同じ引数を使用したfree()の二重呼び出しや、1バイトのオーバーラン(1つずつのバグ)などの単純なエラーに耐えるように設計された特別な(効率の低い)実装が使用されます。 )。ただし、このようなエラーのすべてを保護できるわけではなく、メモリリークが発生する可能性があります。 MALLOC_CHECK_が0に設定されている場合、検出されたヒープの破損はすべてサイレントに無視されます。 1に設定すると、診断メッセージがstderrに出力されます。 2に設定すると、abort(3)がすぐに呼び出されます。 3に設定すると、診断メッセージがstderrに出力され、プログラムは中止されます。ゼロ以外のMALLOC_CHECK_値を使用すると、クラッシュがかなり後で発生する可能性があり、問題の真の原因を追跡するのが非常に困難になるため、便利な場合があります。

9
grigy

たぶん、リーク検出ツールとして Boehmガベージコレクター を使用できます。

http://www.hpl.hp.com/personal/Hans_Boehm/gc/leak.html

サイトから:

#include "leak_detector.h"

main() {
    int *p[10];
    int i;
    /* GC_find_leak = 1; for new collector versions not     */
    /* compiled with -DFIND_LEAK.               */
    for (i = 0; i < 10; ++i) {
    p[i] = malloc(sizeof(int)+i);
    }
    for (i = 1; i < 10; ++i) {
    free(p[i]);
    }
    for (i = 0; i < 9; ++i) {
    p[i] = malloc(sizeof(int)+i);
    }
    CHECK_LEAKS();
}   

(stderr経由で通知を受け取ります)

4
akosch

Macへの移植を始めたときも同じ問題がありました。 「パフォーマンスツールで実行->リーク」だけが私が見つけたものであり、私はそれによってそれほど興奮していません...少なくともCRTDEBUGと比較して。 (ここで他の人が説明しているように)いくつかのオプションがあることは理解していますが、最終的にはマルチプラットフォームであるため、Windowsを使用してリークを探しています。

あなたが静的アナライザーについて言及しているので。 Cのみを実行し、C++を実行しないことがわかるまで、実行するためのホットな計算に時間を費やしました。

3
Nicholaz

私はあなたが説明することを行う「組み込み」のものは何も知りませんが、これの「独自の」バージョンを作成するのはそれほど難しいことではないようです。新しいデバッグで、ポインタ、ファイル、および行をmap<void*, AllocationInfo>に記録する必要があります。ここで、キーは割り当てられたポインタであり、値(AllocationInfo)は、ファイル名、行番号を保持する構造体になります。 、など。また、削除されるポインターについてマップをチェックするカスタム削除演算子を定義する必要があります。見つかった場合、そのエントリはマップから削除されます。次に、プロセスのシャットダウン時に、マップのコンテンツを出力します。

私は 誰かがこのように機能する彼ら自身の自家製のシステムを説明しているページ を見つけました。

3