web-dev-qa-db-ja.com

cまたはc ++で非常に大きなメモリの単一チャンク(> 4GB)を割り当てることができますか?

最近私が思っていた非常に大量のRAMで、4GBより大きいメモリの単一のチャンクを割り当てることは可能ですか?または、小さなチャンクの束を割り当てて、それらの間の切り替えを処理する必要がありますか?

なぜ??? openstreetmap xmlデータの処理に取り組んでいますが、これらのファイルは巨大です。すべてを1つのチャンクにロードすることができないため、現在それらをストリーミングしていますが、mallocまたはnewの上限に興味があるだけです。

43
KPexEA

短い答え:ありそうにない

これを機能させるには、64ビットプロセッサを使用する必要がありますhave。次に、4G以上のRAM=を単一のプロセスに割り当てるためのオペレーティングシステムサポートに依存します。

理論的には可能ですが、メモリアロケータのドキュメントを読む必要があります。また、メモリの断片化の問題の影響を受けやすくなります。

Windowsのメモリ管理 に関する良い情報があります。

27
Benoit

物理および仮想メモリレイアウトの入門書

64ビットCPUとO/Sビルド、そしてワーキングセットのスラッシュを回避するためにほぼ確実に十分なメモリが必要です。背景のビット:

32ビットマシン(概して)には、2 ^ 32(4,294,967,296)の一意の値の1つを格納できるレジスタがあります。これは、32ビットポインターが2 ^ 32の一意のメモリロケーションのいずれかをアドレス指定できることを意味します。これは、魔法の4 GB制限の元となっています。

SPARCV8やXeonなどの一部の32ビットシステムには、より多くの物理メモリを使用できるようにするためのMMUがあります。これにより、複数のプロセスが合計で4GBを超えるメモリを占有することができますが、各プロセスは独自の32ビット仮想アドレス空間に制限されます。仮想アドレス空間を見る単一のプロセスの場合、32ビットのポインターでマップできるのは2 ^ 32の異なる物理的な場所のみです。

詳細については触れませんが、 このプレゼンテーション (警告:PowerPoint)では、これがどのように機能するかを説明しています。一部のオペレーティングシステムには、FPを操作し、異なる物理を交換するための機能 ここ -MMU上記のおかげ)がある)がありますユーザーレベルの制御下にある仮想アドレス空間への場所。

オペレーティングシステムとメモリマップI/Oは仮想アドレス空間の一部を占有するため、その4GBのすべてがプロセスで使用できるとは限りません。例として、Windowsはデフォルトで2GBを使用しますが、/ 3Gスイッチが起動時に呼び出される場合、1GBのみを使用するように設定できます。これは、この種の32ビットアーキテクチャでの単一のプロセスは、メモリ内で4 GB未満の連続したデータ構造しか構築できないことを意味します。

つまり、オーバーレイを手動でスワップするには、Windowsでは [〜#〜] pae [〜#〜] 機能を明示的に使用するか、 Linuxでは同等の機能 を使用する必要があります。これは必ずしも難しいことではありませんが、機能するまでには少し時間がかかります。

あるいは、大量のメモリを備えた64ビットのボックスを入手して、これらの問題を多かれ少なかれ解消することもできます。 64ビットポインタを備えた64ビットアーキテクチャでは、少なくとも理論的には、2 ^ 64(18,446,744,073,709,551,616)もの一意のアドレスを持つ連続したデータ構造を構築できます。これにより、より大きな連続したデータ構造を構築および管理できます。

メモリマップファイルの利点は、4Gbよりはるかに大きなファイル(NTFSではほぼ無限大)を開くことができ、複数の<4Gbメモリウィンドウを使用できることです。
ファイルを開いてメモリに読み込むよりもはるかに効率的です。ほとんどのオペレーティングシステムでは、組み込みのページングサポートを使用しています。

22
Martin Beckett

これは、64ビットOS(およびそれだけのメモリを搭載したマシン)では問題になりません。

Mallocが対応できない場合、OSはメモリを直接割り当てることができるAPIを確実に提供します。 Windowsでは VirtualAlloc APIを使用できます。

14
Rob Walker

これは、使用しているCコンパイラ、および(もちろん)プラットフォームによって異なりますが、連続して利用可能なメモリの最大のチャンクを割り当てることができないという根本的な理由はありません。そしてもちろん、64ビットシステムを使用して多くのRAMよりもアドレス指定する必要があるかもしれません...

履歴と詳細については Malloc を参照してください

alloc.hで HeapMax を呼び出して、使用可能な最大のブロックサイズを取得します。

12
Steven A. Lowe

メモリマップファイルの使用を検討しましたか?非常に大きなファイルをロードしているので、これが最善の方法であると思われるでしょう。

9

これは、OSが4GBを超えるメモリのアドレス指定を可能にする仮想アドレス空間を提供するかどうか、およびコンパイラがnew/mallocを使用したメモリの割り当てをサポートするかどうかによって異なります。

32ビットのWindowsの場合、ポインタサイズが32ビットであるため、4 GBを超える単一のチャンクを取得できず、仮想アドレス空間が4 GBに制限されます。 ( Physical Address Extension を使用して4GBを超えるメモリを取得できますが、そのメモリを4GBの仮想アドレス空間に自分でマップする必要があると思います)

64ビットWindowsの場合、VC++コンパイラーは64ビットポインターをサポートし、仮想アドレス空間の理論上の制限は8TBです。

Linux/gccにも同じことが当てはまると思います。32ビットではできませんが、64ビットではできます。

6
Franci Penov

Robが指摘したように、匿名ファイルのマッピングと同様に、VirtualAlloc for Windowsはこれに適したオプションです。ただし、具体的にはあなたの質問に関して、「CまたはC++の場合」の答えは割り当て可能であり、答えはNO THIS IS NOT SUPPORTED EVEN on WIN7 RC 64

ExeファイルのPE/COFF仕様では、HEAP予約とHEAPコミットを指定するフィールドは32ビットの数量です。これは、Windows CRTでの現在のヒープ実装の物理サイズ制限と一致しています。これは、4GBをわずかに下回っています。したがって、C/C++から4GB以上を割り当てる方法はありません(CreateFileMappingやVirtualAlloc/VirtualAllocNumaなどのOSサポート機能はすべてCまたはC++ではありません)。

また、BE[〜#〜] aware [〜#〜]は、基になるx86またはAMD64 ABI構造体がページテーブルとして知られていることを示します。これ[〜#〜] [〜#〜]は、実際にあなたが確信していることを実行し、これがカーネルメモリで発生している場合でも、より大きなリクエストに小さなチャンクを割り当てます。システム全体に影響があり、これらのテーブルは有限です。

そのような壮大な目的でメモリを割り当てる場合は、割り当ての細分性(VirtualAllocが適用する)に基づいて割り当て、より大きなページを有効にするためのオプションのフラグまたはメソッドを識別することをお勧めします。

4 kbページは386の初期ページサイズで、ペンティアムはその後4 MBを追加しました。現在、 AMD64 (AMDファミリ10hプロセッサ用ソフトウェア最適化ガイド)の最大ページテーブルエントリサイズは1GBです。これは、ここでのケースの場合です。たとえば、4 GBを実行したとしましょう。カーネルのディレクトリに一意のエントリが4つだけあれば、プロセスのメモリを見つけて割り当て、許可することができます。

Microsoftもこれをリリースしました manual これは、アプリケーションメモリの細かい点のいくつかを明確にし、Vista/2008以降のプラットフォームで使用されます。

3

システムでsize_tが32ビットより大きい場合、最初のハードルをクリアしました。ただし、CおよびC++標準は、newまたはmallocへの特定の呼び出しが成功したかどうかを判断する責任はありません(サイズが0のmallocを除く)。これは、OSとヒープの現在の状態に完全に依存します。

3
Dan Olson

他の誰もが言ったように、64ビットマシンを入手するのがよい方法です。しかし、32ビットマシンのIntelマシンでも、OSとCPUが [〜#〜] pae [〜#〜] をサポートしている場合は、4GBを超えるメモリ領域をアドレス指定できます。残念ながら、32ビットWinXPはこれを行いません(32ビットVistaはそうですか?)。 Linuxでは、デフォルトでこれを行うことができますが、ポインタはまだ32ビットであるため、mmap()を使用しても4GBの領域に制限されます。

ただし、すべきことは、オペレーティングシステムにメモリ管理を任せることです。その量のRAMを処理できる環境に入ると、XMLファイルがデータ構造に読み込まれ、スペースが割り当てられます。次に、XMLファイル自体ではなく、メモリ内のデータ構造を操作します。

ただし、64ビットシステムでも、少なくともほとんどのインスタンスでは、OSとMMUこれを自分で処理します。

2
Zachary Hamm