web-dev-qa-db-ja.com

VirtualAllocとHeapAllocの違いは何ですか?

VirtualAllocHeapAllocmallocnewなど、Windows環境でメモリを割り当てる方法はたくさんあります。

したがって、それらの違いは何ですか?

75
user53670

各APIはさまざまな用途に使用されます。また、メモリを使い終わったら、正しい割り当て解除/解放機能を使用する必要があります。

VirtualAlloc

多くのオプションを提供する低レベルのWindows APIですが、主にかなり特定の状況の人々に役立ちます。より大きなチャンクにのみメモリを割り当てることができます(編集:4KBではありません)。あなたがそれを必要とする状況がありますが、あなたがいつこれらの状況の1つにいるのか知っているでしょう。最も一般的なのは、メモリを別のプロセスと直接共有する必要がある場合です。汎用メモリの割り当てには使用しないでください。 VirtualFreeを使用して割り当てを解除します。

HeapAlloc

VirtualAllocより大きなチャンクではなく、要求するメモリのサイズを割り当てます。 HeapAllocは、いつVirtualAllocを呼び出す必要があるかを知っており、自動的に呼び出します。 mallocに似ていますが、Windows専用であり、いくつかのオプションがあります。一般的なメモリチャンクの割り当てに適しています。一部のWindows APIでは、これを使用して渡すAPIを割り当てるか、その仲間HeapFreeを使用して返されるメモリを解放する必要があります。

malloc

メモリを割り当てるCの方法。 C++ではなくCで記述しており、コードを次のように動作させたい場合は、これを優先してください。 Unixコンピュータも、または誰かがそれを使用する必要があると明確に言っています。メモリを初期化しません。 HeapAllocなどの一般的なメモリチャンクの割り当てに適しています。シンプルなAPI。 freeを使用して割り当てを解除します。 Visual C++のmallocHeapAllocを呼び出します。

新着

メモリを割り当てるC++の方法。 C++で記述している場合は、これを優先してください。また、1つまたは複数のオブジェクトを割り当てられたメモリに配置します。 deleteを使用して割り当てを解除します(または配列の場合はdelete[])。 Visual StudioのnewHeapAllocを呼び出してから、呼び出し方に応じてオブジェクトを初期化します。

最近のC++標準(C++ 11以降)では、deleteを手動で使用する必要がある場合は間違っているため、代わりにunique_ptrのようなスマートポインターを使用する必要があります。 C++ 14以降では、newmake_unique()などの関数に置き換えられます)についても同じことが言えます。


また、特定の状況で使用する必要があると言われるSysAllocStringのような他の同様の関数がいくつかあります。

79
Doug

VirtualAllocは、OS仮想メモリ(VM)システムの特殊な割り当てです。 VMシステムでの割り当ては、アーキテクチャに依存する割り当て粒度(割り当て粒度)で行う必要があります。 VMシステムでの割り当ては、メモリ割り当ての最も基本的な形式の1つです。 VM割り当てにはいくつかの形式がありますが、メモリはRAMに専用または物理的にバックアップされているとは限りません(可能ですが)。 VM割り当ては、通常、特別な目的タイプの割り当てです。

  • 非常に大きくなる
  • 共有する必要がある、
  • 特定の値に合わせて調整する必要がある(パフォーマンス上の理由)または
  • 呼び出し側はこのメモリのすべてを一度に使用する必要はありません...
  • 等...

HeapAllocは、本質的にmallocnewの両方が最終的に呼び出すものです。汎用割り当てのさまざまなタイプのシナリオで非常に高速で使用できるように設計されています。これは、古典的な意味での「ヒープ」です。ヒープは、実際にはVirtualAllocによって設定されます。これは、OSから最初に予約スペースを予約するために使用されます。 VirtualAllocによってスペースが初期化された後、HEAPの動作を維持および制御するために、さまざまなテーブル、リスト、およびその他のデータ構造が構成されます。その操作の一部は、動的にヒープをサイズ変更(拡大および縮小)したり、特定の使用法(ある程度のサイズの頻繁な割り当て)にヒープを適応させたりするなどの形式です。

newmallocは多少同じですが、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についても非常にきちんとしたものがあり、この質問に対する回答者は誰も議論していません。

VirtualAllocExは、1つのプロセスがdifferentプロセスのアドレス空間にメモリを割り当てるために使用できるものです。最も一般的には、これが使用されます 組み合わせて CreateRemoteThreadを介して別のプロセスのコンテキストでリモート実行を取得するには(CreateThreadと同様に、スレッドは他のプロセスで実行されます)。

28

メモリ管理を必要とする言語(CやC++など)の使用を計画している場合は、メモリ割り当てAPI(Windows)の違いを理解することが非常に重要です。

enter image description here

これは非常に単純化されたWindows固有のビューであることに注意してください。

この図を理解する方法は、図でメモリ割り当て方法が高いほど、それが使用する高レベル実装であるということです。しかし、下から始めましょう。

カーネルモードメモリマネージャー

オペレーティングシステムのすべてのメモリ予約と割り当て、およびメモリマップファイル共有メモリcopy-on-write操作のサポート、など。ユーザーモードコードから直接アクセスできないため、ここでは省略します。

VirtualAlloc / VirtualFree

これらは、 ユーザーモード から利用可能な最低レベル AP​​Iです。 VirtualAlloc関数は基本的に ZwAllocateVirtualMemory を呼び出し、それがさらに処理を委任するためにring0syscallをすばやく実行します。カーネルメモリマネージャーに。また、ユーザーモードで利用可能なすべてから新しいメモリのブロックを予約/割り当てるための最速の方法です。

ただし、次の2つの主な条件があります。

  • システムの粒度境界で整列されたメモリブロックのみを割り当てます。

  • システムの粒度の倍数のサイズのメモリブロックのみを割り当てます。

では、このシステムの粒度とは何ですか? GetSystemInfo を呼び出すことで取得できます。 dwAllocationGranularity パラメーターとして返されます。その値は実装(および場合によってはハードウェア)固有ですが、多くの64ビットWindowsシステムでは0x10000バイトまたは64Kに設定されます。

つまり、これが意味することは、VirtualAllocを使用して8バイトのメモリブロックを割り当てる場合です。

void* pAddress = VirtualAlloc(NULL, 8, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

成功した場合、pAddress0x10000バイト境界に位置合わせされます。また、8バイトしか要求しなかったとしても、実際のメモリブロックはpage(または、4Kバイトのようなものです。正確なページサイズは dwPageSize パラメーター。)しかし、その上で、pAddressから0x10000バイト(またはほとんどの場合は64K)に及ぶメモリブロック全体はさらなる割り当てのために利用可能になります。したがって、ある意味では、8バイトを割り当てることで、65536を要求することもできます。

したがって、ここでの話の教訓は、アプリケーションの汎用メモリ割り当てをVirtualAllocに置き換えることではありません。以下のheapで行われるように、非常に特殊な場合に使用する必要があります。 (通常、メモリの大きなブロックを予約/割り当てます。)

VirtualAllocを誤って使用すると、深刻なメモリの断片化につながる可能性があります。

HeapCreate / HeapAlloc / HeapFree / HeapDestroy

一言で言えば、heap関数は基本的にVirtualAlloc関数のラッパーです。ここでの他の回答は、それのかなり良い概念を提供します。非常に単純化したビューで、heapが機能する方法は次のとおりです。

  • HeapCreateは、VirtualAllocを内部的に呼び出して(または特定するにはZwAllocateVirtualMemory)、仮想メモリの大きなブロックを予約します。また、仮想メモリの予約ブロック内でさらに小さなサイズの割り当てを追跡できる内部データ構造を設定します。

  • HeapAllocおよびHeapFreeへの呼び出しは、実際には新しいメモリを実際に割り当てたり解放したりしません(もちろん、リクエストがHeapCreateですでに予約されているものを超えていない限り)。meter out(またはcommit)以前に予約された大きなチャンク。ユーザーが要求する小さなメモリブロックに分割します。

  • HeapDestroyは、実際に仮想メモリを解放するVirtualFreeを呼び出します。

したがって、これにより、heap関数は、アプリケーションの汎用メモリ割り当ての完璧な候補になります。任意のサイズのメモリ割り当てに最適です。ただし、heap関数の利便性のために支払う小さな価格は、より大きなメモリブロックを予約するときに、VirtualAllocにわずかなオーバーヘッドを導入することです。

heapのもう1つの良い点は、作成する必要がないことです。通常、プロセスの開始時に自動的に作成されます。そのため、 GetProcessHeap 関数を呼び出すことでアクセスできます。

malloc /無料

heap関数の言語固有のラッパーです。 HeapAllocHeapFreeなどとは異なり、これらの関数は、コードがWindows用にコンパイルされている場合だけでなく、他のオペレーティングシステム(Linuxなど)でも機能します。

これは、Cでプログラミングする場合にメモリを割り当て/解放するための推奨される方法です(ただし、特定のカーネルモードデバイスドライバーをコーディングしている場合を除きます)。

new /削除

高レベル(まあ、C++の場合)メモリ管理オペレーターとして来てください。これらはC++言語に固有であり、mallocCと同様に、heap関数のラッパーでもあります。また、C++固有のコンストラクタの初期化、デストラクタでの割り当て解除、例外の発生などを処理する独自のコードが多数あります。

これらの関数は、C++でプログラミングする場合にメモリとオブジェクトを割り当て/解放するための推奨される方法です。


最後に、プロセス間でメモリを共有するためにVirtualAllocを使用することに関する他の応答で言われたことについて、コメントを1つ作成します。VirtualAlloc自体では、予約/割り当て済み他のプロセスとのメモリ。そのためには、他のプロセスと共有できる名前付き仮想メモリブロックを作成できる CreateFileMapping APIを使用する必要があります。読み取り/書き込みアクセスのためにディスク上で仮想メモリに格納されます。しかし、それは別のトピックです。

23
ahmd0

概要:

  • VirtualAlloc、HeapAllocなどは、OSからさまざまなタイプのメモリを直接割り当てるWindows APIです。 VirtualAllocはWindows仮想メモリシステム内のページを管理し、HeapAllocは特定のOSヒープから割り当てます。率直に言って、それらのいずれかを使用する必要はほとんどありません。

  • mallocは、プロセスにメモリを割り当てる標準C(およびC++)ライブラリ関数です。通常、mallocの実装は、OS APIの1つを使用して、アプリの起動時にメモリのプールを作成し、mallocリクエストを行うときにそこから割り当てます。

  • newは、メモリを割り当てて、そのメモリでコンストラクタを適切に呼び出す標準C++演算子です。 mallocの観点から、またはOS APIの観点から実装できます。この場合、通常はアプリケーションの起動時にメモリプールが作成されます。

7
anon

VirtualAlloc ===> sbrk() UNIXの場合

HeapAlloc ====> malloc() UNIXの場合

4

VirtualAlloc =>仮想メモリに直接割り当て、ブロック単位で予約/コミットします。これは、大きな配列などの大きな割り当てに最適です。

HeapAlloc/new =>は、デフォルトヒープ(または作成できる他のヒープ)にメモリを割り当てます。これはオブジェクトごとに割り当てられ、小さいオブジェクトに最適です。デフォルトのヒープはシリアライズ可能であるため、スレッドの割り当てが保証されています(これにより、高性能シナリオでいくつかの問題が発生する可能性があり、独自のヒープを作成できる理由です)。

malloc =>は、HeapAllocに似たCランタイムヒープを使用しますが、互換性シナリオでは一般的です。

一言で言えば、ヒープとは、(生の仮想メモリではなく)ヒープマネージャによって管理される単なる仮想メモリの塊です。

メモリの世界での最後のモデルはメモリマップファイルです。このシナリオは、大きなファイル(大きなファイルなど)に適しています。これは、EXEを開くときに内部的に使用されます(EXEをメモリにロードせず、メモリマップファイルを作成します)。

2
No hay Problema