適切な割り当て方法の選択
シナリオに適したメモリ割り当て API を選択するには、次のガイダンスを使用します。
| シナリオ | 推奨される API | メモ |
|---|---|---|
| 汎用 C++ の割り当て | new / std::make_unique / std::make_shared |
C++ コードの既定の選択肢。 CRT ヒープを内部的に使用します。 RAII は自動クリーンアップを保証します。 |
| 汎用 C の割り当て | malloc / calloc / realloc |
C コードの既定の選択肢。 プラットフォーム間で移植可能。 |
| 最大 1 MB を超える割り当て、またはページ レベルの制御が必要な割り当て | VirtualAlloc | ページの細分性 (通常は 4 KB) で割り当てます。 特定の保護属性 (PAGE_READWRITE、 PAGE_EXECUTE_READなど) を使用して、大きなアドレス範囲、保護ページ、またはメモリを予約するために使用します。 |
| カスタム コントロールを使用した多数の小さな割り当て (プール アロケーターなど) | HeapAlloc / HeapCreate | 分離またはシリアル化制御用のプライベート ヒープを作成します。
HEAP_NO_SERIALIZEは、ヒープが排他的にシングル スレッドである場合にのみ使用します。 |
| COM 相互運用機能 (マーシャリングされたメモリ) | CoTaskMemAlloc | メモリが COM アパートメントの境界を越えた場合に必要です。 MIDL で生成されたスタブでは、CoTaskMemAlloc/CoTaskMemFree が使用されます。 |
| 移動可能メモリを使用するレガシ コード | GlobalAlloc / LocalAlloc | 新しいコードでは避けてください。 これらは HeapAlloc に対するオーバーヘッドを増やし、主にクリップボード操作およびそれらを必要とする特定の Win32 API との下位互換性のために存在します。 |
Important
割り当てと割り当て解除の関数は常に正しくペアになります。
HeapAllocで割り当てられたメモリは、free()やLocalFreeではなく、HeapFreeで解放する必要があります。 割り当て/割り当て解除ファミリを混在すると、ヒープの破損が原因で診断が困難になります。
Note
VirtualAlloc と HeapAlloc: VirtualAlloc は、ページの細分性で動作します (最小 4 KB、 SYSTEM_INFO.dwAllocationGranularityに合わせた予約、通常は 64 KB)。 VirtualAlloc を使用して多数の小さなオブジェクトを割り当てると、アドレス空間が無駄になります。 小さい頻繁な割り当てには HeapAlloc (または malloc/new) を使用します。 大きなアドレス領域を予約したり、ページ保護を制御したり、カスタム アロケーターを実装したりする必要がある場合は、VirtualAlloc を使用します。
詳細な比較
さまざまなメモリ割り当て方法の簡単な比較を次に示します。
- CoTaskMemAlloc
- GlobalAlloc
- HeapAlloc
- LocalAlloc
- Malloc
- "new"
- VirtualAlloc
GlobalAlloc、LocalAlloc、HeapAlloc の各関数は、最終的に同じヒープからメモリを割り当てますが、それぞれ少し異なる機能セットを提供します。 たとえば、メモリを割り当てられなかった場合は例外を発生するように HeapAlloc に指示できます。 LocalAlloc では使用できない機能です。 LocalAlloc ではハンドルの割り当てがサポートされており、ハンドル値を変更することなく、基になるメモリを再割り当てによって移動できます。 HeapAlloc では使用できません。
32 ビット Windows以降、GlobalAlloc と LocalAlloc は、プロセスの既定のヒープへのハンドルを使用して HeapAlloc を呼び出すラッパー関数として実装されます。 そのため、 GlobalAlloc と LocalAlloc のオーバーヘッドは HeapAlloc よりも大きくなります。
異なるヒープ アロケーターは、さまざまなメカニズムを使用して独特の機能を提供するため、正しい関数を使用してメモリを解放する必要があります。 たとえば、HeapAlloc で割り当てられたメモリは、LocalFree や GlobalFree ではなく HeapFree で解放する必要があります。 GlobalAlloc または LocalAlloc で割り当てられたメモリは、対応するグローバル関数またはローカル関数を使用してクエリ、検証、および解放する必要があります。
VirtualAlloc 関数を使用すると、メモリ割り当ての追加オプションを指定できます。 ただし、割り当てにはページの細分性が使用されるため、 VirtualAlloc を使用するとメモリ使用量が増加する可能性があります。
malloc 関数には、実行時に依存するという欠点があります。 新しい演算子には、コンパイラに依存し、言語に依存するという欠点があります。
CoTaskMemAlloc 関数には、C、C++、またはVisual Basicで適切に機能する利点があります。 MIDL では CoTaskMemAlloc と CoTaskMemFree を使用してメモリをマーシャリングするため、COM ベースのアプリケーションでメモリを共有する唯一の方法でもあります。
例示
関連トピック