質問

背景:大量のジオデータを扱う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ギガも割り当てられないようです。

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

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

役に立ちましたか?

解決

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

LargeAddressAwareフラグを使用してコンパイルする場合、64ビットWindowsでは、4GBのアドレススペース全体を使用できます。これは少し役立ちますが、一般的には、

  • 使用可能なメモリが連続していると想定しないでください。いくつかの大きな割り当てではなく、複数の小さな割り当てで作業できる必要があります。
  • 大量のメモリが必要な場合は、64ビットアプリケーションとしてコンパイルする必要があります。

他のヒント

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

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

ページファイルで可能な限りのメモリを割り当てることができます-/ 3GBスイッチがなくても、4GBのメモリを簡単に割り当てることができます。

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

レイモンド・チェンの例 4GBのメモリを割り当て、その一部をアドレス空間のセクションにマッピングします。

32ビットWindowsでは、最大割り当て可能サイズは64ビットWindowsで16 TBおよび256 TBです。

また、Windowsでメモリ管理がどのように機能するかを本当に知りたい場合は、をお読みください。この記事

ElephantsDreamプロジェクト中、Blender FoundationとBlender 3Dには同様の問題がありました(Mac上では)。リンクを含めることはできませんが、google:blender3dのメモリ割り当ての問題で、最初のアイテムになります。

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

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

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

プロセスごとに合計約2GBを割り当てることができるはずです。 この記事(PDF)の説明詳細。ただし、その大きさに近い単一の連続したブロックを取得することはおそらくできないでしょう。

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

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

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

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

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top