DLL のアンロード時にメモリ リークが発生すると、ホスト プロセスでリークが発生しますか?

StackOverflow https://stackoverflow.com/questions/132242

質問

次の場合を考えてみましょう。

dll = LoadDLL()
dll->do()

...
void do() {
    char *a = malloc(1024);
}
...

UnloadDLL(dll);

この時点で、malloc() の呼び出しで割り当てられた 1k はホスト プロセスで再び利用できるようになりますか?DLL は CRT に静的にリンクしています。

役に立ちましたか?

解決

いいえ、漏れません。

DLL モデル (静的、動的) を混在させる場合、DLL にメモリを割り当て、それを別の DLL で解放すると (または exe で解放すると)、メモリ エラーが発生する可能性があります。

これは、静的にリンクされた CRT によって作成されたヒープが、別の DLL の CRT と同じヒープではないことを意味します。

CRT の動的バージョンにリンクすると、動的にリンクされたすべての CRT 間でヒープが共有されるため、リークが発生します。つまり、常に動的 CRT を使用するようにアプリを設計するか、DLL の境界を越えてメモリを管理しないようにする必要があります (つまり、DLL にメモリを割り当てる場合は、常に同じ DLL 内でメモリを解放するルーチンを提供します)。

他のヒント

  1. OS によって追跡されるプロセスによって使用されるメモリは、DLL に固有のものではなく、プロセス全体に適用されます。

  2. メモリは、OS によってヒープと呼ばれるチャンク単位でプログラムに与えられます。

  3. ヒープ マネージャー (malloc / new など) はチャンクをさらに分割し、要求元のコードに渡します。

  4. 新しいヒープが割り当てられた場合にのみ、OS はメモリの増加を検出します。

  5. DLL が C ランタイム ライブラリ (CRT) に静的にリンクされている場合、DLL のコードが呼び出す CRT 関数を含む CRT のプライベート コピーがコンパイルされ、DLL のバイナリに置かれます。Mallocもこれに含まれます。

  6. この malloc のプライベート コピーは、静的にリンクされた DLL 内に存在するコードがメモリを割り当てようとするたびに呼び出されます。

  7. その結果、malloc のこのコピーにのみ表示されるプライベート ヒープが、この malloc によって OS から取得され、コードによって要求されたメモリがこのプライベート ヒープ内に割り当てられます。

  8. DLL がアンロードされると、そのプライベート ヒープもアンロードされ、ヒープ全体が OS に返されるため、このリークは気づかれません。.

  9. ただし、DLL が動的にリンクされている場合、メモリは malloc の単一の共有バージョンによって割り当てられ、共有モードでリンクされているすべてのコードにグローバルになります。

  10. このグローバル malloc によって割り当てられるメモリは、動的別名共有モードでリンクされている他のすべてのコードに使用されるヒープでもあるヒープから取得され、したがって共通です。したがって、このヒープからのリークはプロセス全体に影響を与えるリークになります。

編集 - リンク シナリオの説明を追加しました。

それはわかりません。これは、静的および動的 CRT の実装によって異なります。にもよるかもしれません サイズ これは、大きな割り当てを OS に転送する CRT が存在しますが、小さな割り当てに対しては独自のヒープを実装しているためです。

液漏れするブラウン管の問題は、もちろん液漏れです。リークしない CRT の問題は、malloc されたメモリは free が呼び出されるまで使用可能なままである必要があるため、実行可能ファイルがメモリを使用することを合理的に想定している可能性があることです。

MSDN より DLL 境界を越えて CRT オブジェクトを渡す際の潜在的なエラー

CRTライブラリの各コピーには、別個の明確な状態があります。そのため、ファイルハンドル、環境変数、ロケールなどのCRTオブジェクトは、これらのオブジェクトが割り当てまたは設定されているCRTのコピーに対してのみ有効です。DLLとそのユーザーがCRTライブラリのさまざまなコピーを使用している場合、これらのCRTオブジェクトをDLL境界に渡すことはできず、反対側で正しくピックアップすることを期待することはできません。

また、CRTライブラリの各コピーには独自のHeap Managerがあるため、1つのCRTライブラリにメモリを割り当て、DLL境界にポインターを渡して、CRTライブラリの別のコピーによって解放されるためにポインターを渡すことは、ヒープ腐敗の潜在的な原因です。

お役に立てれば。

実は、マークされた答えは間違っています。まさに漏れがあります。各 DLL が独自のヒープを実装し、シャットダウン時に解放することは技術的には可能ですが、ほとんどの「ランタイム」ヒープ (静的または動的) は Win32 プロセス ヒープ API のラッパーです。

これに当てはまらないことを保証する特別な注意を払っていない限り、DLL はロード、ドゥ、アンロード サイクルごとに割り当てをリークします。

テストを行って、メモリ リークがあるかどうかを確認することもできます。毎回 1 MB を割り当てて簡単なテストを 30 回実行します。それはすぐに理解する必要があります。

一つ確かなことがある。DLL にメモリを割り当てた場合は、そのメモリ (DLL 内) も解放する必要があります。

たとえば、次のようなもの (シンプルだが直感的な疑似コード) が必要です。

dll = DllLoad();

ptr = dll->alloc();

dll->free(ptr);

DllUnload(dll);

DLL には元のプロセス (DLL をロードする) とは異なるヒープがあるため、これを行う必要があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top