2009-04-11 20 views
2

私のアプリケーションの中にはいくつかのリファレンスクラスがあります。また、これらのアプリケーションが使用するdllにも、IRefCountedインターフェイスを継承して実装しています。C++:リファレンスカウントシステムでのメモリリークのデバッグ

これらのメモリリークの原因を見つけるのを助けるために、私はそれぞれのアプリケーションがこれらのすべてのrefrence countedクラスのリストを既存の状態に維持したいと思っています。

問題は、これらのリストの使用がクラスの使用に影響を与えないように、これらのリストのインスタンスを管理することです(たとえば、いつもポインタをリストに渡す必要はありません。プロセス)。

- これらのアプリケーションのいくつかは、すぐに実行され、同じdllを使用する可能性があります。各アプリケーションは独自のオブジェクトリストを必要とし、そのアプリケーションによってロードされるすべてのdllなどはそのリストを使用する必要があります(ただし、複数のアプリケーションによって1つのDLLが読み込まれる可能性があります)。
- リストが破棄されるときリストに残されたオブジェクトは、truleyが正しく解放されなかったものであるように、アプリケーション内の他のすべてのグローバル変数と静的変数の後にリストを破棄する必要があります。

次に、リストのデストラクタにブレークポイントを追加するだけで、デバッガ内の割り当てられていないオブジェクトを調べることができます。

+0

ご自身のご質問はありますか? –

答えて

1

私はあなたがCOMを使用していると思います。weak pointerという具合に、インスタンス化されたオブジェクトのレジストリが破壊されないようにする必要があるでしょう。

すべてのクラスを変更できる場合は、静的メンバーを挿入してすべてのインスタンスを追跡し、インスタンスのデストラクタを静的メンバーから削除することができます。たとえば、次のように基底クラスやユーティリティクラスを使用することができます:あなたはクラスの種類ごとに異なるレジストリをしたい場合はプロセス場合

class InstanceRegistry { 
protected: 
    InstanceRegistry() { 
     registry.insert(this); 
    } 
    ~InstanceRegistry() { 
     registry.remove(this); 
    } 
private: 
    static SomeContainerType<InstanceRegistry*> registry; 
}; 

余分な作業は

+0

私はCOMを使用していないので、オブジェクトのコン/デストラクタに何かを追加して、リストから削除することができます。リストprobsはオブジェクトへの参照を持ってはいけません。 –

+0

COMはIRefCountedではなくIUnknownを使用します。 –

+0

ありがとうございます。 COMノートが打ち切られました。 –

1

など、実行する必要があります同じDLLを使用している場合、各プロセスはそのDLLの静的(または "グローバル")データの専用コピーを取得します。

あなたがする必要があるのは、リストをDLL内のグローバル変数にして、すべてのアプリケーションからそのDLLにリンクするだけです。そうすれば、何か別のものを渡す必要はありません。

マルチDLLプロセスでオブジェクトが破壊される順序が予測できないため、リストの破壊をトラップするというのは困難です。

mainまたはWinMain機能の最後にリストの内容をダンプする方がはるかに簡単です。

スマートポインタクラスを一貫して使用していない場合は、そうするようにしてください。また、循環参照カウントを探す価値があるかもしれません。オブジェクトAはオブジェクトBにカウントを持っています。これは、リリースされていないオブジェクトの一般的な原因です。

更新:

実行して、オブジェクトを解放するために、すべての静的デストラクタを強制するには、あなたが、あなたは、あなたのアプリケーション特定の方法を構築する必要があります、その後、リスト内のエントリを調べることができます。

プロセスを起動する非常に最小限のEXEがあり、実際にすべての作業を実行する他のDLLが多数ロードされているとします。これらの他のDLLは、何とか(おそらくCOMまたはCOMライクなシステムによって)LoadLibraryによってロードされます。 LoadLibrary APIは、DLLをプロセスにロードするか、DLLがすでにロードされている場合はDLLの内部参照カウンタをインクリメントして動作します。 FreeLibrary APIは、カウンタがゼロになるまでカウンタをデクリメントしてから、DLLをアンロードします(その時点で、そのDLLの静的デストラクタが実行されます)。

ここで、未処理の参照カウントされたすべてのオブジェクトのリストを保持する診断DLLを追加します。他のすべてのDLLは、診断DLLへのimport-libリンケージを使用し、EXEも同様にLoadLibraryを使用します。

mainが終了しようとすると、EXEは以前にロードしたDLLハンドルのリストを調べ、それらのすべてでFreeLibraryを呼び出します。診断DLLをロードしたままにすることで、それが最後にまだ存在することを保証します。それは少なくとも理論です。

しかし、他のDLLはどの順序でアンロードする必要がありますか? A.DLLにB.DLLで定義されたオブジェクトへの静的ポインタがある場合は、まずAをアンロードする方がよいでしょう。したがって、さまざまなDLLがどのように「レイヤード」アーキテクチャを形成しているかを知る必要があります。下位レイヤに応じて上位レイヤが配置されるため、アンロードする順序が安全です。

また、一度すべてのDLLをアンロードすると、DLL内のオブジェクトを参照する診断リスト内のエントリは、ヒープ上の有効なデータを指すようになりますが、vtableは定義されたコードを指しています現在アンロードされているDLLによって、これらのオブジェクトで仮想関数を呼び出すことはできません。あなたは彼らのデータを調べることができるはずです。

+0

winmainの最後にリストをダンプする際の問題は、静的または大域的なスマートポインタにはまだリフレクションがあり、オブジェクトが破壊されたときにオブジェクトを解放するので完全に安全です。そのようなスマートなポインタが破壊された後、このリストの状態を実際に確認する必要があります。 –

+0

静的変数とグローバル変数の99%が.exeモジュールにあり、リストの後にまだアンロードされているようです。 –

+0

私はdllとしてアプリケーションをビルドし、リストを含むホストexeを持っていて、アプリケーションをロードし、そのアプリケーションでWinMainを呼び出し、WinMainが返ってくるとリストをアンロードしてダンプすると思いますか? –