VirtualAlloc
、HeapAlloc
、malloc
、new
など、Windows環境でメモリを割り当てる方法はたくさんあります。
したがって、それらの違いは何ですか?
各APIはさまざまな用途に使用されます。また、メモリを使い終わったら、正しい割り当て解除/解放機能を使用する必要があります。
多くのオプションを提供する低レベルのWindows APIですが、主にかなり特定の状況の人々に役立ちます。より大きなチャンクにのみメモリを割り当てることができます(編集:4KBではありません)。あなたがそれを必要とする状況がありますが、あなたがいつこれらの状況の1つにいるのか知っているでしょう。最も一般的なのは、メモリを別のプロセスと直接共有する必要がある場合です。汎用メモリの割り当てには使用しないでください。 VirtualFree
を使用して割り当てを解除します。
VirtualAlloc
より大きなチャンクではなく、要求するメモリのサイズを割り当てます。 HeapAlloc
は、いつVirtualAlloc
を呼び出す必要があるかを知っており、自動的に呼び出します。 malloc
に似ていますが、Windows専用であり、いくつかのオプションがあります。一般的なメモリチャンクの割り当てに適しています。一部のWindows APIでは、これを使用して渡すAPIを割り当てるか、その仲間HeapFree
を使用して返されるメモリを解放する必要があります。
メモリを割り当てるCの方法。 C++ではなくCで記述しており、コードを次のように動作させたい場合は、これを優先してください。 Unixコンピュータも、または誰かがそれを使用する必要があると明確に言っています。メモリを初期化しません。 HeapAlloc
などの一般的なメモリチャンクの割り当てに適しています。シンプルなAPI。 free
を使用して割り当てを解除します。 Visual C++のmalloc
はHeapAlloc
を呼び出します。
メモリを割り当てるC++の方法。 C++で記述している場合は、これを優先してください。また、1つまたは複数のオブジェクトを割り当てられたメモリに配置します。 delete
を使用して割り当てを解除します(または配列の場合はdelete[]
)。 Visual Studioのnew
はHeapAlloc
を呼び出してから、呼び出し方に応じてオブジェクトを初期化します。
最近のC++標準(C++ 11以降)では、delete
を手動で使用する必要がある場合は間違っているため、代わりにunique_ptr
のようなスマートポインターを使用する必要があります。 C++ 14以降では、new
(make_unique()
などの関数に置き換えられます)についても同じことが言えます。
また、特定の状況で使用する必要があると言われるSysAllocString
のような他の同様の関数がいくつかあります。
VirtualAlloc
は、OS仮想メモリ(VM)システムの特殊な割り当てです。 VMシステムでの割り当ては、アーキテクチャに依存する割り当て粒度(割り当て粒度)で行う必要があります。 VMシステムでの割り当ては、メモリ割り当ての最も基本的な形式の1つです。 VM割り当てにはいくつかの形式がありますが、メモリはRAMに専用または物理的にバックアップされているとは限りません(可能ですが)。 VM割り当ては、通常、特別な目的タイプの割り当てです。
HeapAlloc
は、本質的にmalloc
とnew
の両方が最終的に呼び出すものです。汎用割り当てのさまざまなタイプのシナリオで非常に高速で使用できるように設計されています。これは、古典的な意味での「ヒープ」です。ヒープは、実際にはVirtualAlloc
によって設定されます。これは、OSから最初に予約スペースを予約するために使用されます。 VirtualAlloc
によってスペースが初期化された後、HEAPの動作を維持および制御するために、さまざまなテーブル、リスト、およびその他のデータ構造が構成されます。その操作の一部は、動的にヒープをサイズ変更(拡大および縮小)したり、特定の使用法(ある程度のサイズの頻繁な割り当て)にヒープを適応させたりするなどの形式です。
new
とmalloc
は多少同じですが、malloc
は本質的にHeapAlloc( heap-id-default )
;の正確な呼び出しです。 new
ただし、[追加] C++objectsに割り当てられたメモリを構成できます。特定のオブジェクトについて、C++はvtableを各呼び出し元のヒープに格納します。これらのvtableは、実行のためのリダイレクトであり、C++にOO特性(継承、関数のオーバーロードなど)を与えるものの一部を形成します。
_alloca()
や_malloca()
などの他の一般的な割り当て方法は、stackベースです。 FileMappingsは実際にVirtualAlloc
で割り当てられ、それらのマッピングをFILE
型に指定する特定のビットフラグで設定されます。
ほとんどの場合、そのメモリの使用と一貫した方法でメモリを割り当てる必要があります;)。 C++ではnew
、Cではmalloc
、大規模な場合はVirtualAlloc
、またはIPCの場合。
***注:HeapAlloc
によって行われた大きなメモリ割り当ては、実際には、ある程度のサイズ(100 kまたは16 MBか、忘れてしまいますが、かなり大きい:))後にVirtualAlloc
に出荷されます。
***編集IPCとVirtualAlloc
について簡単に発言しましたが、関連するVirtualAlloc
についても非常にきちんとしたものがあり、この質問に対する回答者は誰も議論していません。
VirtualAlloc
Exは、1つのプロセスがdifferentプロセスのアドレス空間にメモリを割り当てるために使用できるものです。最も一般的には、これが使用されます 組み合わせて CreateRemoteThreadを介して別のプロセスのコンテキストでリモート実行を取得するには(CreateThread
と同様に、スレッドは他のプロセスで実行されます)。
メモリ管理を必要とする言語(CやC++など)の使用を計画している場合は、メモリ割り当てAPI(Windows)の違いを理解することが非常に重要です。
これは非常に単純化されたWindows固有のビューであることに注意してください。
この図を理解する方法は、図でメモリ割り当て方法が高いほど、それが使用する高レベル実装であるということです。しかし、下から始めましょう。
オペレーティングシステムのすべてのメモリ予約と割り当て、およびメモリマップファイル、共有メモリ、copy-on-write操作のサポート、など。ユーザーモードコードから直接アクセスできないため、ここでは省略します。
これらは、 ユーザーモード から利用可能な最低レベル APIです。 VirtualAlloc
関数は基本的に ZwAllocateVirtualMemory を呼び出し、それがさらに処理を委任するためにring0
にsyscallをすばやく実行します。カーネルメモリマネージャーに。また、ユーザーモードで利用可能なすべてから新しいメモリのブロックを予約/割り当てるための最速の方法です。
ただし、次の2つの主な条件があります。
システムの粒度境界で整列されたメモリブロックのみを割り当てます。
システムの粒度の倍数のサイズのメモリブロックのみを割り当てます。
では、このシステムの粒度とは何ですか? GetSystemInfo を呼び出すことで取得できます。 dwAllocationGranularity
パラメーターとして返されます。その値は実装(および場合によってはハードウェア)固有ですが、多くの64ビットWindowsシステムでは0x10000
バイトまたは64K
に設定されます。
つまり、これが意味することは、VirtualAlloc
を使用して8バイトのメモリブロックを割り当てる場合です。
void* pAddress = VirtualAlloc(NULL, 8, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
成功した場合、pAddress
は0x10000
バイト境界に位置合わせされます。また、8バイトしか要求しなかったとしても、実際のメモリブロックはpage
(または、4K
バイトのようなものです。正確なページサイズは dwPageSize
パラメーター。)しかし、その上で、pAddress
から0x10000
バイト(またはほとんどの場合は64K
)に及ぶメモリブロック全体はさらなる割り当てのために利用可能になります。したがって、ある意味では、8バイトを割り当てることで、65536を要求することもできます。
したがって、ここでの話の教訓は、アプリケーションの汎用メモリ割り当てをVirtualAlloc
に置き換えることではありません。以下のheapで行われるように、非常に特殊な場合に使用する必要があります。 (通常、メモリの大きなブロックを予約/割り当てます。)
VirtualAlloc
を誤って使用すると、深刻なメモリの断片化につながる可能性があります。
一言で言えば、heap関数は基本的にVirtualAlloc
関数のラッパーです。ここでの他の回答は、それのかなり良い概念を提供します。非常に単純化したビューで、heapが機能する方法は次のとおりです。
HeapCreate
は、VirtualAlloc
を内部的に呼び出して(または特定するにはZwAllocateVirtualMemory
)、仮想メモリの大きなブロックを予約します。また、仮想メモリの予約ブロック内でさらに小さなサイズの割り当てを追跡できる内部データ構造を設定します。
HeapAlloc
およびHeapFree
への呼び出しは、実際には新しいメモリを実際に割り当てたり解放したりしません(もちろん、リクエストがHeapCreate
ですでに予約されているものを超えていない限り)。meter out(またはcommit
)以前に予約された大きなチャンク。ユーザーが要求する小さなメモリブロックに分割します。
HeapDestroy
は、実際に仮想メモリを解放するVirtualFree
を呼び出します。
したがって、これにより、heap関数は、アプリケーションの汎用メモリ割り当ての完璧な候補になります。任意のサイズのメモリ割り当てに最適です。ただし、heap関数の利便性のために支払う小さな価格は、より大きなメモリブロックを予約するときに、VirtualAlloc
にわずかなオーバーヘッドを導入することです。
heapのもう1つの良い点は、作成する必要がないことです。通常、プロセスの開始時に自動的に作成されます。そのため、 GetProcessHeap 関数を呼び出すことでアクセスできます。
heap関数の言語固有のラッパーです。 HeapAlloc
、HeapFree
などとは異なり、これらの関数は、コードがWindows用にコンパイルされている場合だけでなく、他のオペレーティングシステム(Linuxなど)でも機能します。
これは、Cでプログラミングする場合にメモリを割り当て/解放するための推奨される方法です(ただし、特定のカーネルモードデバイスドライバーをコーディングしている場合を除きます)。
高レベル(まあ、C++
の場合)メモリ管理オペレーターとして来てください。これらはC++
言語に固有であり、malloc
のC
と同様に、heap
関数のラッパーでもあります。また、C++
固有のコンストラクタの初期化、デストラクタでの割り当て解除、例外の発生などを処理する独自のコードが多数あります。
これらの関数は、C++
でプログラミングする場合にメモリとオブジェクトを割り当て/解放するための推奨される方法です。
最後に、プロセス間でメモリを共有するためにVirtualAlloc
を使用することに関する他の応答で言われたことについて、コメントを1つ作成します。VirtualAlloc
自体では、予約/割り当て済み他のプロセスとのメモリ。そのためには、他のプロセスと共有できる名前付き仮想メモリブロックを作成できる CreateFileMapping
APIを使用する必要があります。読み取り/書き込みアクセスのためにディスク上で仮想メモリに格納されます。しかし、それは別のトピックです。
概要:
VirtualAlloc、HeapAllocなどは、OSからさまざまなタイプのメモリを直接割り当てるWindows APIです。 VirtualAllocはWindows仮想メモリシステム内のページを管理し、HeapAllocは特定のOSヒープから割り当てます。率直に言って、それらのいずれかを使用する必要はほとんどありません。
mallocは、プロセスにメモリを割り当てる標準C(およびC++)ライブラリ関数です。通常、mallocの実装は、OS APIの1つを使用して、アプリの起動時にメモリのプールを作成し、mallocリクエストを行うときにそこから割り当てます。
newは、メモリを割り当てて、そのメモリでコンストラクタを適切に呼び出す標準C++演算子です。 mallocの観点から、またはOS APIの観点から実装できます。この場合、通常はアプリケーションの起動時にメモリプールが作成されます。
VirtualAlloc
===> sbrk()
UNIXの場合
HeapAlloc
====> malloc()
UNIXの場合
VirtualAlloc
=>仮想メモリに直接割り当て、ブロック単位で予約/コミットします。これは、大きな配列などの大きな割り当てに最適です。
HeapAlloc
/new
=>は、デフォルトヒープ(または作成できる他のヒープ)にメモリを割り当てます。これはオブジェクトごとに割り当てられ、小さいオブジェクトに最適です。デフォルトのヒープはシリアライズ可能であるため、スレッドの割り当てが保証されています(これにより、高性能シナリオでいくつかの問題が発生する可能性があり、独自のヒープを作成できる理由です)。
malloc
=>は、HeapAlloc
に似たCランタイムヒープを使用しますが、互換性シナリオでは一般的です。
一言で言えば、ヒープとは、(生の仮想メモリではなく)ヒープマネージャによって管理される単なる仮想メモリの塊です。
メモリの世界での最後のモデルはメモリマップファイルです。このシナリオは、大きなファイル(大きなファイルなど)に適しています。これは、EXEを開くときに内部的に使用されます(EXEをメモリにロードせず、メモリマップファイルを作成します)。