8

背景: 大量の地理データを扱う C++ プログラムを作成しており、大きなチャンクを一度にロードして処理したいと考えています。私は、32 ビット マシン用にコンパイルされたアプリを使用することに制約されています。私がテストしているマシンは 64 ビット OS (Windows 7) を実行しており、6 ギガの RAM を搭載しています。MS VS 2008 を使用しています。

次のコードがあります。

byte* pTempBuffer2[3];
try
{
    //size_t nBufSize = nBandBytes*m_nBandCount;
    pTempBuffer2[0] = new byte[nBandBytes];
    pTempBuffer2[1] = new byte[nBandBytes];
    pTempBuffer2[2] = new byte[nBandBytes];
}
catch (std::bad_alloc)
{
    // If we didn't get the memory just don't buffer and we will get data one
    // piece at a time.
    return;
}

アプリが 32 ビット アドレス指定の 4 ギガバイトの制限に達するまで、メモリを割り当てることができることを期待していました。ただし、nBandBytes が 466,560,000 の場合、2 回目の試行で新しい std::bad_alloc がスローされます。この段階では、プロセスのワーキング セット (メモリ) の値は 665,232 K です。そのため、1 ギガのメモリを割り当てることさえできないようです。

32 ビット Windows でのアプリケーションの制限は 2 ギガであることが言及されていますが、これは win32 の /3GB スイッチで 3 ギガに拡張される可能性があります。これはその環境では良いアドバイスですが、このケースには関係ありません。

64 ビット OS で 32 ビット アプリケーションを使用する場合、どれくらいのメモリを割り当てることができますか?

4

8 に答える 8

11

OSがあなたに与えたいと思っているのと同じくらい。デフォルトでは、Windows は 32 ビット プロセスに 2GB のアドレス空間を持たせます。そして、これはいくつかのチャンクに分割されます。スタック用に 1 つの領域が確保され、ロードされる実行可能ファイルと dll ごとに別の領域が確保されます。残っているものはすべて動的に割り当てることができますが、それが 1 つの大きな連続したチャンクになるという保証はありません。それぞれ数百 MB のいくつかの小さなチャンクである可能性があります。

LargeAddressAware フラグを指定してコンパイルすると、64 ビット Windows で 4GB のアドレス空間をすべて使用できるようになるため、少しは役に立ちますが、一般的には、

  • 使用可能なメモリが連続していると想定しないでください。いくつかの大きな割り当てではなく、複数の小さな割り当てで作業できるはずです。
  • 多くのメモリが必要な場合は、64 ビット アプリケーションとしてコンパイルする必要があります。
于 2009-06-23T17:48:25.267 に答える
6

Windows 32 ビットでは、通常のプロセスで最大 2 GB を使用できますが、/3GBスイッチを使用すると 3 GB に達する可能性があります (Windows 2003 の場合)。

しかし、あなたの場合、連続したメモリを割り当てていると思うので、例外が発生しました。

于 2009-06-23T17:45:09.497 に答える
4

ページ ファイルが許す限り多くのメモリを割り当てることができます。/3GB スイッチがなくても、4GB のメモリを問題なく割り当てることができます。

この記事を読む物理メモリ、仮想メモリ、およびアドレス空間 (3 つすべてが異なるもの) について考える方法の概要について説明します。簡単に言えば、RAM とまったく同じ量の物理メモリがありますが、アプリはその物理メモリとまったくやり取りしません。仮想メモリにデータを保存するのに便利な場所です。仮想メモリはページファイルのサイズによって制限され、アプリが使用できる量は他のアプリが使用している量によって制限されます (ただし、実際に使用しない限り、より多くを割り当てることができます)。32 ビット世界でのアドレス空間は 4GB です。これらのうち、2 GB がカーネルに割り当てられます (/3BG スイッチを使用する場合は 1 GB)。残っている 2GB のうち、一部はスタックによって、一部は現在実行中のプログラム (およびすべての dll など) によって使用されます。これ' 断片化され、連続したスペースしか取得できなくなります。これが、割り当てが失敗する場所です。しかし、そのアドレス空間は、割り当てられた仮想メモリにアクセスするための便利な方法にすぎないため、より多くのメモリを割り当てて、そのチャンクを一度にいくつかアドレス空間に持ち込むことができます。

Raymond Chen は、 4GB のメモリを割り当て、その一部をアドレス空間のセクションにマップする方法の例を示しています。

32 ビット Windows では、割り当て可能な最大容量は 16 TB であり、64 ビット Windows では 256 TB です。

また、Windows でのメモリ管理のしくみについて詳しく知りたい場合は、この記事をお読みください。

于 2009-06-23T18:05:06.253 に答える
2

ElephantsDream プロジェクトの間、Blender 3D を使用する Blender Foundation にも同様の問題がありました (Mac 上ではありましたが)。リンクを含めることはできませんが、グーグル:blender3dのメモリ割り当ての問題で、最初の項目になります。

ソリューションには、ファイル マッピングが含まれていました。自分で試したことはありませんが、ここで読むことができます:http://msdn.microsoft.com/en-us/library/aa366556(VS.85).aspx

于 2009-06-23T18:07:07.590 に答える
1

Sysinternals VMMapは、仮想アドレス空間の断片化を調査するのに最適です。これにより、割り当て可能な連続メモリの量が制限される可能性があります。空き領域を表示するように設定し、サイズで並べ替えて最大の空き領域を見つけ、アドレスで並べ替えて最大の空き領域(おそらく、リベースされたDLL、共有メモリ領域、またはその他のヒープ)を分離しているものを確認することをお勧めします。

他の人が示唆しているように、極端に大きな連続した割り当てを避けるのがおそらく最善です。

LARGE_ADDRESS_AWARE=YESアプリケーションが依存するライブラリが互換性がある限り、設定(jalfが提案するように)は適切です。その場合は、AllocationPreferenceレジストリキーを設定してコードをテストし、トップダウンの仮想アドレス割り当てを有効にする必要があります。

于 2009-06-23T18:23:21.293 に答える
1

nBandBytes が 466,560,000 の場合、1.4 GB を割り当てようとしています。通常、32 ビット アプリは 2 GB のメモリにしかアクセスできません (/3GB で起動し、実行可能ファイルが大きなアドレス空間対応としてマークされている場合は、それ以上になります)。メモリの大きなチャンクに対して、連続したアドレス空間のブロックを多数見つけるのは難しいかもしれません。

64 ビット OS でギガバイト単位のメモリを割り当てたい場合は、64 ビット プロセスを使用します。

于 2009-06-23T17:49:24.920 に答える
1

プロセスごとに合計約 2GB を割り当てることができるはずです。こちらの記事(PDF)で詳しく解説しています。ただし、そのサイズに近い単一の連続したブロックを取得することはおそらくできません。

于 2009-06-23T17:51:37.257 に答える
1

小さいチャンクで割り当てても、必要なメモリを取得できませんでした。特に、周囲のプログラムのメモリ動作が予測できない場合や、別のオペレーティング システムで実行する必要がある場合はそうです。私の経験では、32 ビット プロセスのヒープ領域の上限は約 1.2GB です。

この量のメモリでは、手動でディスクに書き込むことをお勧めします。メモリを管理し、必要に応じて一時ファイルに書き込むクラスで配列をラップします。願わくば、あなたのプログラムの特性が、ディスクにあまり影響を与えずにそのデータの一部を効果的にキャッシュできるようなものであることを願っています。

于 2009-06-23T18:03:00.467 に答える