この場合を考えてみましょう:
dll = LoadDLL()
dll->do()
...
void do() {
char *a = malloc(1024);
}
...
UnloadDLL(dll);
この時点で、malloc()の呼び出しで割り当てられた1kは、ホストプロセスで再び使用できるようになりますか?DLLはCRTに静的にリンクしています。
この場合を考えてみましょう:
dll = LoadDLL()
dll->do()
...
void do() {
char *a = malloc(1024);
}
...
UnloadDLL(dll);
この時点で、malloc()の呼び出しで割り当てられた1kは、ホストプロセスで再び使用できるようになりますか?DLLはCRTに静的にリンクしています。
OSによって追跡されるプロセスによって使用されるメモリは、DLLに固有ではなく、プロセス全体に適用できます。
メモリは、ヒープと呼ばれるOSによってチャンクでプログラムに与えられます
ヒープマネージャー(malloc / newなど)はさらにチャンクを分割し、要求しているコードに渡します。
新しいヒープが割り当てられた場合にのみ、OSはメモリの増加を検出します。
DLLがCランタイムライブラリ(CRT)に静的にリンクされている場合、DLLのコードが呼び出すCRT関数を含むCRTのプライベートコピーがコンパイルされ、DLLのバイナリに配置されます。Mallocもこれに含まれています。
このmallocのプライベートコピーは、静的にリンクされたDLL内に存在するコードがメモリを割り当てようとするたびに呼び出されます。
したがって、このmallocのコピーにのみ表示されるプライベートヒープは、このmallocによってOSから取得され、このプライベートヒープ内のコードによって要求されたメモリを割り当てます。
DLLがアンロードされると、プライベートヒープがアンロードされ、ヒープ全体がOSに戻されるため、このリークは認識されません。
ただし、DLLが動的にリンクされている場合、メモリは、共有モードでリンクされているすべてのコードにグローバルな、mallocの単一の共有バージョンによって割り当てられます。
このグローバルmallocによって割り当てられたメモリは、ヒープから出力されます。ヒープは、動的別名共有モードでリンクされているため、一般的な他のすべてのコードに使用されるヒープでもあります。したがって、このヒープからのリークは、プロセス全体に影響を与えるリークになります。
編集-リンクシナリオの説明を追加しました。
わかりません。これは、静的および動的 CRT の実装によって異なります。OS に大きな割り当てを転送する CRT があるため、割り当てのサイズに依存することもありますが、小さな割り当てには独自のヒープを実装します。
リークする CRT の問題は、もちろんリークすることです。リークしない CRT の問題は、malloc されたメモリは free が呼び出されるまで使用可能なままであるため、実行可能ファイルがメモリを使用することを合理的に期待する可能性があることです。
実際、マークされた答えは正しくありません。その通り漏れがあります。各 dll が独自のヒープを実装し、シャットダウン時に解放することは技術的には可能ですが、ほとんどの "ランタイム" ヒープ (静的または動的) は Win32 プロセス ヒープ API のラッパーです。
これが当てはまらないことを保証するために特別な注意を払っていない限り、dll はロード、実行、アンロードのサイクルごとに割り当てをリークします。
MSDN の潜在的なエラーから、DLL の境界を越えて CRT オブジェクトを渡す
CRT ライブラリの各コピーには、別個の個別の状態があります。そのため、ファイル ハンドル、環境変数、ロケールなどの CRT オブジェクトは、これらのオブジェクトが割り当てられている、または設定されている CRT のコピーに対してのみ有効です。DLL とそのユーザーが CRT ライブラリの異なるコピーを使用する場合、これらの CRT オブジェクトを DLL の境界を越えて渡すことはできず、反対側で正しく取得されることを期待できません。
また、CRT ライブラリの各コピーには独自のヒープ マネージャーがあるため、1 つの CRT ライブラリにメモリを割り当て、ポインターを DLL 境界を越えて渡して CRT ライブラリの別のコピーによって解放すると、ヒープが破損する可能性があります。
お役に立てれば。
テストを実行して、メモリ リークがあるかどうかを確認できます。毎回 1 MB を割り当てる簡単なテストを 30 回実行します。あなたはそれをすぐに理解する必要があります。
1つのことは確かです。DLL にメモリを割り当てた場合は、そのメモリも解放する必要があります (DLL 内)。
たとえば、次のようなもの (シンプルだが直感的な疑似コード) が必要です。
dll = DllLoad();
ptr = dll->alloc();
dll->free(ptr);
DllUnload(dll);
DLL には元のプロセス (DLL をロードするプロセス) とは異なるヒープがあるため、これを行う必要があります。
いいえ、漏れません。
dll モデル (静的、動的) を混在させると、メモリを dll に割り当て、別のモデルで解放する (または exe で解放する) と、メモリ エラーが発生する可能性があります。
これは、静的にリンクされた CRT によって作成されたヒープが、別の dll の CRT と同じヒープではないことを意味します。
CRT の動的バージョンとリンクした場合、動的にリンクされたすべての CRT 間でヒープが共有されるため、リークが発生します。これは、常に動的 CRT を使用するようにアプリを設計するか、dll の境界を越えてメモリを管理しないようにする必要があることを意味します (つまり、dll でメモリを割り当てる場合は、常に同じ dll でメモリを解放するルーチンを提供します)。