トップ回答者
確保できるメモリの大きさに関して

質問
回答
-
OSは、32bitOSですか?32bit アプリですか?
もしどちらか一方でも満たすのであれば、通常は、リニアに確保できるメモリは、2GiByte - コードやほかのデータで使っていない領域となります。
実際は、スタックエリアや、あれこれとられて、どんなに小さなプログラムでも1.8Gよりも多く取れることはほとんどありません。
#実際にそれくらいの部分が不連続領域として存在するため
この数字だと、おおむね1.5G程度ですので、確保できてる領域としてはかなり優秀なほうです。
ちなみに、int で表現できる数値は 2G までというのはご存知ですよね?
2G以上確保したいのであれば、OSを64bitOSにし、アプリも64bitアプリにした上で、数字計算部分を SIZE_T に変更するなどすることをお勧めします。
わんくま同盟,Microsoft MVP for Windows-SDK (Oct 2005 - Sept 2007) [http://blogs.wankuma.com/tocchann/]- 回答としてマーク クサキ 2009年2月26日 5:35
-
ちょっと補足を。
積んでいる物理メモリサイズが4GBとのことですが、仮想記憶/ページファイルがあるため、プログラムからアクセス可能なメモリ量とはあまり関係がありません。
その上で、ポインタは32bit型で4GBまでのアドレスを表現することができます。こちらは論理アドレスと呼ばれます。
この論理アドレスの中でプログラムが確保可能な領域が2GB、残り2GBがOSとなっています。
(ここからはとっちゃんさんの説明やリンクにつながります。)
あとVistaとのことですので、リンクオプション/LARGEADDRESSAWARE (大きいアドレスの処理)を指定して2GB以上のメモリに対応したプログラムであることを宣言し、
BCDEdit /set increaseuserva 3072と設定変更してOS再起動を行うと、32bit版であっても3GBまで使用可能になります。
とはいえ、今時なら64bit環境への移行をおすすめします。- 回答としてマーク クサキ 2009年2月26日 5:35
-
今のところ、挙げられている64bitアプリケーションとする、3GBオプションを使うというのは、開発側だけでは対応しきれないということもご理解下さい。
アプリケーションを使用するユーザに、64bit環境を用意するなり、3GBオプションを設定してもらうなりの要求をする(使える人を制限する)ことになります。
そういったユーザ環境への制約を与える前に、本当に、同時に大量のメモリ領域が必要なのか見直して下さい。
ケースにもよりますが、ファイルに一旦書き出して、後で再利用するというように、作業を分割できることも多いと思います。
もちろん、PCとセットで販売するソフトウェアであれば、64bitOSの載ったPCとセットで販売する前提で、64bitアプリケーションとして作ることも十分選択肢としてあり得ます。
解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。- 回答としてマーク クサキ 2009年2月26日 5:35
-
> もしどちらか一方でも満たすのであれば、通常は、リニアに確保できるメモリは、
2GiByteは1プロセスあたりの上限値になります。
> 2GiByte - コードやほかのデータで使っていない領域となります。
1つのプログラム(プログラム自体やスタックエリアや、あれこれ)で合わせて2Gまでということですか?
それとも、仮にメモリを6G積んで、配列を分割し非連続でも構わないとしたら、
目的の配列を2G以上確保できるということでしょうか?
メモリを6G積んでもまず、32bitOS上では4G以下しか使用できません。
アドレスを表す範囲が32bit=4GByteとなります。
また、物理メモリが3GByteというのもこれが原因で、理論上は4GByteまで表せるのですが、実際はハードウェアにアクセスするためのアドレスなどに使用されるため多くて3.5GByte程度しかメモリとして使用できません。
- 回答としてマーク クサキ 2009年2月26日 5:36
-
クサキ さん の発言:連続・非連続問わず、(通常は)2GB以上のユーザ領域を確保することはできません。
> もしどちらか一方でも満たすのであれば、通常は、リニアに確保できるメモリは、
> 2GiByte - コードやほかのデータで使っていない領域となります。
1つのプログラム(プログラム自体やスタックエリアや、あれこれ)で合わせて2Gまでということですか?
それとも、仮にメモリを6G積んで、配列を分割し非連続でも構わないとしたら、
目的の配列を2G以上確保できるということでしょうか?
# AWEとかいう仕組みがあるので、絶対にできないと言い切れませんが、使ったことがないのでできるとも言えません。
# http://msdn.microsoft.com/en-us/library/aa366527(VS.85).aspx
クサキ さん の発言:現在、ユーザーインターフェースの方がVB6.0ですので、すぐには64Bit化は無理ですよね?
VB6.0の部分もC++で作り、また64Bit対応した場合は逆に32BitのOSでは動かなくなるのですか?64bit化はVB6の時点で無理なはずです。
http://support.microsoft.com/kb/894373/jaなお、64bitアプリケーションは32bitOSでは実行できません。
クサキ さん の発言:とりあえずは現状で、お客さんに上限がどこまでかを言いたいのですが、
はっきりした数字を出すのは難しそうですね。経験的にこのくらいというしかなさそうですね。1GB越えるようなメモリが必要になった時点で設計を見直すことを考えるべきでしょう。(連続領域であれば、もっと小さい領域から危険視しなければならない)
リアルタイムに処理するといっても、本当に2GB以上のデータを同時に持っておかないと駄目なんですか?
データを吸い出して、キャッシュファイルに退避して、時間差で処理とか、吸い出しが終わってから処理とか、可能性はないのでしょうか?
解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。- 回答としてマーク クサキ 2009年2月26日 5:36
-
こんにちは。
# いろんな側面からのお話が出てるようですね~。
元の質問、 「2GBのメモリーを、またそれ以上を確保することは出来ないのですか?」 というところに戻って言えば、32 ビット OS で普通の状況 (3GB オプションを考えない) なら、答えは 「できません」 です。
その他、注意点や詳細については、私は佐祐理さんのご指摘に全面的に賛成です。
-------------------------------
だどさん http://keicode.com/ -
リアルタイムのニュアンスが不明なんですが
確保できたとしても,その後ずっと物理メモリ上に居座るとは限らないので,
ずっと物理メモリ上から零れ落ちない(ページアウト)ようにしておきたいのなら,
ワーキングセットを広げておいて( SetProcessWorkingSetSize )
仮想メモリ確保( VirtualAlloc )後に
そこをロック( VirtualLock )してやれば
ページフォルト自体は起きなくなります。
(ただ,めいっぱい確保してしまうのはまずい)
物理的に確保できたとして,
基本的にはその2GBを複数のプロセス(≒アプリ)で奪い合うので,
実機と似た環境でテストしてみないといけないかも。
稍丼 / yayadon- 回答としてマーク クサキ 2009年2月26日 5:38
すべての返信
-
OSは、32bitOSですか?32bit アプリですか?
もしどちらか一方でも満たすのであれば、通常は、リニアに確保できるメモリは、2GiByte - コードやほかのデータで使っていない領域となります。
実際は、スタックエリアや、あれこれとられて、どんなに小さなプログラムでも1.8Gよりも多く取れることはほとんどありません。
#実際にそれくらいの部分が不連続領域として存在するため
この数字だと、おおむね1.5G程度ですので、確保できてる領域としてはかなり優秀なほうです。
ちなみに、int で表現できる数値は 2G までというのはご存知ですよね?
2G以上確保したいのであれば、OSを64bitOSにし、アプリも64bitアプリにした上で、数字計算部分を SIZE_T に変更するなどすることをお勧めします。
わんくま同盟,Microsoft MVP for Windows-SDK (Oct 2005 - Sept 2007) [http://blogs.wankuma.com/tocchann/]- 回答としてマーク クサキ 2009年2月26日 5:35
-
過去の似たようなスレッドと言うことで貼り付けておきます。
http://social.msdn.microsoft.com/forums/ja-JP/vsgeneralja/thread/1741dcfe-c438-47dc-9115-d4800a661cba/
http://social.msdn.microsoft.com/forums/ja-JP/vcgeneralja/thread/abd8676c-cf10-4b77-bc70-40aa623bd1ec/
解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。 -
ちょっと補足を。
積んでいる物理メモリサイズが4GBとのことですが、仮想記憶/ページファイルがあるため、プログラムからアクセス可能なメモリ量とはあまり関係がありません。
その上で、ポインタは32bit型で4GBまでのアドレスを表現することができます。こちらは論理アドレスと呼ばれます。
この論理アドレスの中でプログラムが確保可能な領域が2GB、残り2GBがOSとなっています。
(ここからはとっちゃんさんの説明やリンクにつながります。)
あとVistaとのことですので、リンクオプション/LARGEADDRESSAWARE (大きいアドレスの処理)を指定して2GB以上のメモリに対応したプログラムであることを宣言し、
BCDEdit /set increaseuserva 3072と設定変更してOS再起動を行うと、32bit版であっても3GBまで使用可能になります。
とはいえ、今時なら64bit環境への移行をおすすめします。- 回答としてマーク クサキ 2009年2月26日 5:35
-
今のところ、挙げられている64bitアプリケーションとする、3GBオプションを使うというのは、開発側だけでは対応しきれないということもご理解下さい。
アプリケーションを使用するユーザに、64bit環境を用意するなり、3GBオプションを設定してもらうなりの要求をする(使える人を制限する)ことになります。
そういったユーザ環境への制約を与える前に、本当に、同時に大量のメモリ領域が必要なのか見直して下さい。
ケースにもよりますが、ファイルに一旦書き出して、後で再利用するというように、作業を分割できることも多いと思います。
もちろん、PCとセットで販売するソフトウェアであれば、64bitOSの載ったPCとセットで販売する前提で、64bitアプリケーションとして作ることも十分選択肢としてあり得ます。
解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。- 回答としてマーク クサキ 2009年2月26日 5:35
-
> OSは、32bitOSですか?32bit アプリですか?
OSは Vista 32Bitで、32bit アプリです。
リアルタイムで動かしたいのでメインメモリを使いたいです。
> もしどちらか一方でも満たすのであれば、通常は、リニアに確保できるメモリは、
> 2GiByte - コードやほかのデータで使っていない領域となります。
1つのプログラム(プログラム自体やスタックエリアや、あれこれ)で合わせて2Gまでということですか?
それとも、仮にメモリを6G積んで、配列を分割し非連続でも構わないとしたら、
目的の配列を2G以上確保できるということでしょうか?
現在、ユーザーインターフェースの方がVB6.0ですので、すぐには64Bit化は無理ですよね?
VB6.0の部分もC++で作り、また64Bit対応した場合は逆に32BitのOSでは動かなくなるのですか?とりあえずは現状で、お客さんに上限がどこまでかを言いたいのですが、
はっきりした数字を出すのは難しそうですね。経験的にこのくらいというしかなさそうですね。追加の質問ですが、タスクマネージャーを見ると、物理メモリが、
3GBぐらいしかありませんが、残りの1GBはどうなっているのでしょう?
-
> もしどちらか一方でも満たすのであれば、通常は、リニアに確保できるメモリは、
2GiByteは1プロセスあたりの上限値になります。
> 2GiByte - コードやほかのデータで使っていない領域となります。
1つのプログラム(プログラム自体やスタックエリアや、あれこれ)で合わせて2Gまでということですか?
それとも、仮にメモリを6G積んで、配列を分割し非連続でも構わないとしたら、
目的の配列を2G以上確保できるということでしょうか?
メモリを6G積んでもまず、32bitOS上では4G以下しか使用できません。
アドレスを表す範囲が32bit=4GByteとなります。
また、物理メモリが3GByteというのもこれが原因で、理論上は4GByteまで表せるのですが、実際はハードウェアにアクセスするためのアドレスなどに使用されるため多くて3.5GByte程度しかメモリとして使用できません。
- 回答としてマーク クサキ 2009年2月26日 5:36
-
クサキ さん の発言:連続・非連続問わず、(通常は)2GB以上のユーザ領域を確保することはできません。
> もしどちらか一方でも満たすのであれば、通常は、リニアに確保できるメモリは、
> 2GiByte - コードやほかのデータで使っていない領域となります。
1つのプログラム(プログラム自体やスタックエリアや、あれこれ)で合わせて2Gまでということですか?
それとも、仮にメモリを6G積んで、配列を分割し非連続でも構わないとしたら、
目的の配列を2G以上確保できるということでしょうか?
# AWEとかいう仕組みがあるので、絶対にできないと言い切れませんが、使ったことがないのでできるとも言えません。
# http://msdn.microsoft.com/en-us/library/aa366527(VS.85).aspx
クサキ さん の発言:現在、ユーザーインターフェースの方がVB6.0ですので、すぐには64Bit化は無理ですよね?
VB6.0の部分もC++で作り、また64Bit対応した場合は逆に32BitのOSでは動かなくなるのですか?64bit化はVB6の時点で無理なはずです。
http://support.microsoft.com/kb/894373/jaなお、64bitアプリケーションは32bitOSでは実行できません。
クサキ さん の発言:とりあえずは現状で、お客さんに上限がどこまでかを言いたいのですが、
はっきりした数字を出すのは難しそうですね。経験的にこのくらいというしかなさそうですね。1GB越えるようなメモリが必要になった時点で設計を見直すことを考えるべきでしょう。(連続領域であれば、もっと小さい領域から危険視しなければならない)
リアルタイムに処理するといっても、本当に2GB以上のデータを同時に持っておかないと駄目なんですか?
データを吸い出して、キャッシュファイルに退避して、時間差で処理とか、吸い出しが終わってから処理とか、可能性はないのでしょうか?
解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。- 回答としてマーク クサキ 2009年2月26日 5:36
-
#実際にやるかどうかは別ですが...回避方法は?というだけの話なら
要件にもよるけど
メモリ・マップ・ファイル (Memory-Mapped Files)
という仕組みを使う( CreateFileMapping )と
16EiB までの データ を扱えます。
といっても
(ドライブ上に)作成可能なファイルの大きさまでですけどね。
実際にデータにアクセスするときは
全体のデータの中で
対象とする場所を設定( MapViewOfFile )して
読みand/or書き
設定を解除( UnmapViewOfFile )
するかたちになります。
ただし
MapViewOfFile する時に仮想メモリを使うときと同じ制限をうけるので
一度にMapする量を2GiBとかは無理です。
ということは,大きなデータの場合は,
固定長ファイルのレコードをランダムアクセスするような感じになるので
上記の繰り返しになります。
なので
(システム側にバッファの仕組みがあるので
毎度書き込みが発生するわけではないですけど)
要件にパフォーマンスがあうかはわかりません。
感じとしては
256MB の物理メモリのマシンで
1GBのデータを扱ってる時の感じでしょう。
一度に複数箇所 Mapすることも可能なので
MoveMemory でぺロ~ンとやるのも可能です。
Mapする開始位置の決まりもあるので
扱うデータのデータ長との関係でややこしい面があるけど
うまくクラスにラップしてやれば扱いが楽になるかも。
全箇所使わないのならスパース・ファイルと組み合わせると
実際には場所を取らなくていいかもしれません。
cf.
Advanced Windows 第5版 下
の 第17章 の 特に Memory-Mapped Data Files や
Processing a Big File Using Memory-Mapped Files の箇所。
あまりこのあたりのことに詳しくない場合は
上巻 第3章 と 下巻 PartⅢ 第13~18章 は
すべて読まないといけないかもしれません。
上 巻 もあります。
並列して計算をやらせるのなら
スレッド のところも読んで
クラスを作りこまないといけないかも。
原書は上下なく一冊です。
Windows Via C/C++
稍丼 / yayadon -
こんにちは。
# いろんな側面からのお話が出てるようですね~。
元の質問、 「2GBのメモリーを、またそれ以上を確保することは出来ないのですか?」 というところに戻って言えば、32 ビット OS で普通の状況 (3GB オプションを考えない) なら、答えは 「できません」 です。
その他、注意点や詳細については、私は佐祐理さんのご指摘に全面的に賛成です。
-------------------------------
だどさん http://keicode.com/ -
リアルタイムのニュアンスが不明なんですが
確保できたとしても,その後ずっと物理メモリ上に居座るとは限らないので,
ずっと物理メモリ上から零れ落ちない(ページアウト)ようにしておきたいのなら,
ワーキングセットを広げておいて( SetProcessWorkingSetSize )
仮想メモリ確保( VirtualAlloc )後に
そこをロック( VirtualLock )してやれば
ページフォルト自体は起きなくなります。
(ただ,めいっぱい確保してしまうのはまずい)
物理的に確保できたとして,
基本的にはその2GBを複数のプロセス(≒アプリ)で奪い合うので,
実機と似た環境でテストしてみないといけないかも。
稍丼 / yayadon- 回答としてマーク クサキ 2009年2月26日 5:38
-
リアルタイムとは秒30コマのビデオレートのことを指しています。
ビデオを取り込みながら何らかの処理をし結果を記録したいということです。
現在でも、出来る計算もあれば出来ない計算もあります。
出来ない計算は将来的にはマルチコアのCPUでリアルタイム性を確保しようと考えているくらいです。
そんな分けでファイルに落とすことは難しいと思っています。例えば、10分間記録するためには、30*60*10=18,000枚の画像が必要になります。
スペックとしてもなるべく大きな値を表明したいと思っています。
ただ、多くのアプリケーションの場合は10MByteもあれば大丈夫で、32Bitの安いPCでも動くことも重要です。当面は、VB6.0のユーザーインターフェースをC++のCLRで書き換えようと思っています。
具体的な必要に迫られたら、3GB オプションも検討したいと思います。
また、具体的には問題になっていませんが、
>ワーキングセットを広げておいて( SetProcessWorkingSetSize )
>仮想メモリ確保( VirtualAlloc )後にそこをロック( VirtualLock )してやれば
>ページフォルト自体は起きなくなります。
という対処もしなければならない場面も出てくるかもしれません。 -
クサキ の発言:コンピュータにおけるリアルタイムというと一般にリアルタイムシステムを指します。
リアルタイムとは秒30コマのビデオレートのことを指しています。
また、具体的には問題になっていませんが、
>ワーキングセットを広げておいて( SetProcessWorkingSetSize )
>仮想メモリ確保( VirtualAlloc )後にそこをロック( VirtualLock )してやれば
>ページフォルト自体は起きなくなります。
という対処もしなければならない場面も出てくるかもしれません。
ですのでyayadonさんも「ニュアンスが不明」と指摘されています。きっと「素早く」程度の意味だと思いますが、誤解を招きますので。
VirtualLock()にも書かれていますが、ページフォールトを避ける目的でVirtualLock()を使用すると「ページをメモリにロックすると、利用可能な RAM が減少するため、他の重要なページがページングファイルにスワップアウトされて、システムのパフォーマンスが低下することがあります。」
つまり、他プロセスやOS本体がページフォールトを起こし、その度にページファイルの読み書きが頻発し、ディスクI/Oが遅くなり、それにつられて結局、自身のアプリケーションが遅くなります。
なのでお勧めしません。この辺りのパラメータはWindows側に任せることを勧めします。
(Windowsのメモリ割り当て戦略を熟知した上で、その欠点を回避するために特定のページをロックするなら別ですが、そのレベルの質問とは見受けられませんでしたので。)
逆に3GBの方は有効です。
-
3Gオプションについては、ちょっとだけ補足。。。
VB6もVC6も3Gオプションをつけてもロードアドレスが変わるわけではないので、効果のほどは疑問符満載です。
ま、そのあたりはともかく、どのくらいの画像サイズなのか知りませんが、18000枚連続した一本のメモリイメージじゃないと操作できないものなのでしょうか?
動画のようなもののようですが、一つの莫大な配列じゃないと操作できない仕組みなのだとしたらまずそこを改めることを検討したほうがいいと思いますよ。
みなさんが言ってるのは、そういうことです。
10分分の画像18000枚を常にオンメモリで保持していなければいけないプログラムの仕組みですか?
そうじゃないのだとしたら、メモリから退避する仕組みを何かしら考慮するなりしたほうがいいと思います。
一般的なストリーミング処理や、巨大画像編集などは、着目点とその周辺部だけをメモリ上に保持しておき
それ以外の分はテンポラリアウトするなどして、利用メモリ量をあまり増やしすぎないようにするのが一般的な対策です。
わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/ -
メモリ・マップ・ファイル(memory-mapped files)ですが,
バッファとして利用する目的で,
書き込み用と読み込み用のビューを
同じ場所に対してそれぞれ作成する形で行けば,
それぞれのビューの仮想アドレスは別になりますが
実際の物理アドレスは同じ場所をさしています。
読み込み用のビューのUnmapするタイミングに気をつけながら
うまく移動していけば,
(確保できるからといって
メモリ上に前もって大量のバッファを確保しておいても
ワーキングセットの関係でずるずるとページアウトしてしまうから,
実際に使用する際にはページフォルト発生で
ページ・インが必要になり,
幸いソフト・ページフォルトだってとしても
少なからずパフォーマンスに影響が出てしまいます。
また,
入ってくるデータ量が前もって不明な場合はとくに)
有効な手段の内のひとつだと思うんですけどね。
稍丼 / yayadon -
色んなアプリケーションを動かすために、中心となるDLLの仕様です。
高速性、大容量、汎用性、開発の効率の間での妥協の産物でもあります。30[f/s]で640×480[pixl] 8bitモノクロで簡単な処理もあります。
今のままでも、100秒程度はメモリに問題なく記録できるようになりました。
4096*4096の画像も扱うこともあります。動画もありますが、実際には静止画の方が多いかもしれません。
18000枚連続というのは今直面している問題ではなく、スペックとしてなるべく大きい値を書きたいということと、
容量的な質問させてもらう中で出てきたものです。
1.5確保できると書いていますが、これも今回質問するために簡単なプログラムを書いた時の結果です。
本番のシステムでは1G程度です。高速化をとことん考えれば、連続したメモリの方がより良いと思います。ただ、大した差でもないとも思います。
逆に、非連続でも確保しても使えるメモリは(すくなくとも専用のPCとして使う場合)少し増えるだけでした。
VirtualLock()は物理メモリ上から零れ落ちない(ページアウト)ようにできるとのことで参考になりまっした。
4GBのPCを簡単に準備することも可能な時代になり、1GBそれに当てても、特に専用のシステムのために
使うのは問題ないとも考えます。
3GB オプションも参考になりました。ただ、現在何れをとっても、今困っている問題ではありませんで、
私の結論としては、時間のセーブのため何もしないということと。
今のままでも画像のため1G程度は利用できるということです。
何か、問題が発生したら、これらのことを参考に対処したいと考えています。