2012-04-14 10 views
3

私はC++で書いたDLLを持っています。 ただし、GlobalAlloc()を使用してメモリを割り当てます。メモリリークを避けるために、私はこれらの割り当てを追跡し、DLLの破棄時にそれらの割り当てをすべて解除する必要があります。C++ DLLアンロードデストラクタ?

私のDLLがアンロードされたときに呼び出される関数を書く方法はありますか? 私が考えることができることの1つは、DLL内にグローバルオブジェクトを作成し、デストラクタにメモリフリーコールを書き込むことですが、これは過度のようです。 私の他のアイデアは、DLLがアンロードされるときにメモリを解放するためにオペレーティングシステムに依存することですが、これは汚れているようです。

ありがとうございました

+0

メモリは、LPCSTR GetCSV()関数が呼び出されたときに割り当てられます。基本的には、ローカルの標準文字列のメモリをメモリにコピーしています。私はGlobalAlloc()を使用して割り当てます。関数が返ってから呼び出し元がメモリにアクセスできるようにします。 GetCSV()への古い呼び出しからメモリをクリーンアップするコードをいくつか追加しましたが、DLLがアンロードされたときの最終的なケースは処理されません。これは明らかに自動的に行われます。この[記事](http://blogs.msdn.com/b/oldnewthing/archive/2012/01/05/10253268.aspx)(回答者によってリンクされています)、本当にいいです。 – Amil

答えて

6

私のDLLがアンロードされたときに呼び出される関数を書く方法はありますか?私はあなたのオブジェクトのデストラクタは未定義になりますと呼ばれる正確にいつ信じるが、私は、私のDLL内のグローバルオブジェクトを作成し、そのデストラクタが可能です

でメモリ無料通話を書いていると考えることができます一つのこと。

あなたはDLL_PROCESS_DETACHに興味があるかもしれませんが、DllMainで重要なことを避けるべきですが、ここではリソースを解放することが許容されているようです。警告に注意してください。DLLは、プロセスのDLL、終了、もしくはにFreeLibraryへの呼び出しの失敗負荷の結果としてプロセスからアンロードされると

、システムは、DLLのエントリポイントを呼び出すことはありませんプロセスの個々のスレッドのDLL_THREAD_DETACH値を指定します。 DLLには、DLL_PROCESS_DETACH通知のみが送信されます。 DLLは、この機会に、DLLが認識しているすべてのスレッドのすべてのリソースをクリーンアップすることができます。

DLL_PROCESS_DETACHを処理するときに、DLLが動的にアンロードされる場合(lpReservedパラメータがNULL)、ヒープメモリなどのリソースを解放する必要があります。プロセスが終了する場合(lpvReservedパラメータがNULLでない場合)、現在のスレッド以外のプロセス内のすべてのスレッドが既に終了しているか、ExitProcess関数の呼び出しによって明示的に終了しているため、ヒープ矛盾した状態でこの場合、DLLがリソースをクリーンアップすることは安全ではありません。代わりに、DLLは、オペレーティングシステムがメモリを再利用できるようにする必要があります。あなたはDLLによって作成された多数のオブジェクトを持っている場合あなたのDLLは、メモリを保持することができますなぜについて詳しく説明する必要があるかもしれません

は、彼らが定義されたライフサイクルを持っているし、彼らの人生の終わりに自分自身をクリーンアップする必要があります。

メモリが割り当てられ、関数を介して呼び出し元に返されます)なぜDLLを消費している人に責任を負わせるのでしょうか?彼らは記憶を解放することができます。ターミナルサービスライブラリは、このパターン(WTSFreeMemory)に従います。

リソースが長寿命で、ライブラリの有効期間中にが必要な場合は、消費者がライブラリのライフサイクルを制御できるようにします。 2つの関数:MyFrameworkStartupMyFrameworkShutdownを適切に記述します。 Winsockはこのパターンに従います(WSAStartupWSACleanup)。

私の他のアイデアは、DLLのアンロード時にオペレーティングシステムを使用してメモリを解放するだけですが、これは汚れているようです。

You'll be okay if the process is exiting

メモリを解放を心配しないでください。プロセスのアドレス空間が破壊されると、すべてが消えてしまいます。ハンドルを閉じることを心配しないでください。プロセスハンドルテーブルが破棄されると、ハンドルは自動的に閉じられます。他のDLLは既にDLL_PROCESS_DETACH通知を受け取っている可能性があるため、他のDLLを呼び出そうとしないでください。その場合、デストラクタが実行された後にDelphiオブジェクトを使用しようとすると、 。

「何もしない」戦略を実行する前に、記事全体とコメントを読んで理解してください。

+0

ありがとう!これは完璧です。特に、メモリを解放することを心配する必要がないことについての注意。 – Amil

2

どのようにメモリが割り当てられていますか?通常、最も良い選択肢は、何らかの対称性(コンストラクタの割り当て、デストラクタの割り当て解除、またはDLLがロードされたときに割り当てられたメモリ、DLLがアンロードされたときに解放される)を保持しようとすることです。

いずれの場合でも、DLLがアンロードされたときに通知する場合は、DllMain関数、特にDLL_PROCESS_DETACHパラメータを調べます。

+1

与えられたリンクに従って、ランタイムライブラリによって提供される標準DllMainは、グローバルオブジェクトのコンストラクタ/デストラクタを呼び出します。したがって、私は、適切なコンストラクタ/デストラクタでDLL内のグローバルオブジェクトを使用するだけで十分だと思います。 – celtschk

+0

お返事ありがとうございます!メモリは、 'LPCSTR GetCSV()'関数が呼び出された時に割り当てられます。基本的には、メモリをローカルの標準文字列からメモリにコピーしています。関数が返った後に呼び出し元がメモリにアクセスできるようにするために、 'GlobalAlloc() 'を使って割り当てます。私は古い呼び出しから 'GetCSV()'へのメモリをクリーンアップするコードをいくつか追加しましたが、DLLがアンロードされる最後のケースは処理されません。これは明らかに自動的に行われます。 – Amil

1

DLLがアンロードされると、fdwReasonをDLL_PROCESS_DETACHに設定して、DllMain functionが呼び出されます。ドキュメントに記載されているように、lpvReservedの値を確認し、NULLの場合は空きメモリだけを確認してください。あなたはshould not free memory if the process is terminatingです。

+0

素敵で簡単な答えをありがとう! – Amil