3

私はメモリリークツールを開発しています。これで、新しい演算子と削除演算子をオーバーロードしています。その正常に動作します。しかし、このツールを作成しているコードは約 15000 行です。既存のコードを変更することはできませんが、メモリリーク ツール関数を既存のコードに呼び出すことができます。stl コンテナー (リスト、マップ、スタックなど) を持つ既存のコード。Stl コンテナーは、new および delete 演算子も呼び出して、メモリの割り当てまたは割り当て解除を行います。stl コンテナが、オーバーロードされた new および delete ではない new および delete 演算子を呼び出す必要があることを望みます。例:

int *iptr = new int[10] ----> should call overloaded new[]
delete [] iptr -------------> should call overloaded delete[]
map.insert(10) -------------> should call default new[] ( which are in new.h)
map.erase()  ---------------> should call default delete[] ( which are in new.h)

どうすればできますか?どんな助けでも感謝します。

申し訳ありませんが、new と delete を次のマクロに置き換えていることを忘れていました。

#define new DEBUG_NEW
#define DEBUG_NEW TrackMemory(__FILE__, __LINE__) ->* new
#define delete TrackDelete(__FILE__, __LINE__); delete

ここで、TrackMemory はメモリを追跡するために使用され、new は delete と同じようにメモリを割り当てるために使用されます。私のツールも正常に動作しますが、stl コンテナーが表示されると、オーバーロードされた new のみを使用するため、間違った結果が得られます。私を助けてください

4

3 に答える 3

3

これらの「空の」関数を書くことから始めます。それらは標準のnewを置き換え、独自のもので削除します。

void *operator new (size_t memorySize);
void *operator new[] (size_t memorySize);
void *operator new (size_t memorySize, const std::nothrow_t &) throw ();
void *operator new[] (size_t memorySize, const std::nothrow_t &) throw ();
void operator delete (void *memoryPointer);
void operator delete[] (void *memoryPointer);
void operator delete (void *memoryPointer, const std::nothrow_t &) throw ();
void operator delete[] (void *memoryPointer, const std::nothrow_t &) throw ();

次に、個別の関数を記述して、メモリの割り当てと割り当て解除を行います。

void *myNew (size-t memorySize);
void myDelete (void *memoryPointer);

最初に述べた関数でmyNewとmyDeleteを呼び出します。

HeapAllocとHeapFreeを使用して、myNewとmyDeleteを実装します。

次に、グローバル変数を作成し、次のようにマークします(これはVisual Studioです)。

#pragma init_seg(lib)

これにより、グローバル変数が最初に初期化され、最後にクリーンアップされます。

これまで、基本について説明してきました。実際のリークレポート機能を取得するには、割り当てられたメモリに関する情報をmyNew関数に保存する必要があります。

グローバル変数のデストラクタを使用して、すべてのリークを報告します。

さらに、StackWalkを使用して呼び出しスタックを取得し、これを各メモリ割り当てとともに保存することもできます。

他のツールを使用する代わりに、なぜこれを実行したいのか疑問に思う人もいるかもしれません。

  • 私の経験では、VisualStudioでのリークレポートは限られています。コールスタックは表示されませんが、直接の呼び出し元のみが表示されるため、意味がありません。
  • 一部のツールは#defineを使用してnew、delete、alloc、...を置き換えますが、これにより、かなりの場合に問題が発生する可能性があります(たとえば、freeと呼ばれるクラスメソッド(Qtでこれを参照)、または削除がヘッダーで行われる、ただし、リンクする必要がある.libの新しい(Qtでも見られます))。
  • 他のツールでは、アプリケーションのインタラクティブなスナップショットを作成し、後でそれらを比較する必要があります。上記の私のアプローチでは、自動リークレポートを取得します(手動によるアクションは不要で、常にアプリケーションの最後にあります...)。

独自のメモリマネージャを入手したら、他の機能の追加について考え始めることができます(たとえば、コールスタックに基づくメモリ統計、メモリの上書きを見つけるためのトリック、削除後にメモリを再利用するコードを見つけるためのトリックなど)。

于 2011-02-09T14:15:02.490 に答える
2

15000行? newコード内のラッパー メソッドへのすべての呼び出しとラッパー メソッドへの呼び出しを置き換えれdeleteば (マクロを使用してログに記録__FILE____LINE__、最初のステップにすることができます)、すぐに完了します。

または、 valgrindなどの既存のツールを使用します。

于 2011-02-09T12:43:06.647 に答える
0

演算子 new をオーバーロードしているという意味が明確ではありません。標準演算子 new 自体をオーバーロードすることはできません。リンク時にのみ置き換えることができます。交換すると元のものを失います。これは私が今まで見た中で最もばかげたデザインです。交換もグローバルです。一部のプラットフォームでは、プラットフォーム固有のリンカー トリック (弱いシンボル) を使用して、これを回避できます。

クラスベースの演算子 new を使用して、ある種の検索トリックを実行できます。もちろん、配置引数で演算子 new をオーバーロードすることもできますが、これらのどちらも意味していないと思います。

于 2011-02-09T12:42:57.737 に答える