アプリ版:「スタンプのみでお礼する」機能のリリースについて

教えてgooの識者のお知恵をお借りしたくご質問させていただきます。
表記の通り、C&C++を用いて、大容量のメモリ確保をスワップ無しで行いたく考えております。
質問の内容としてましては、(1)、(2)の2点があります。

(1) 「VirtualAllocに失敗するという理由としてどのような原因があるのでしょうか?」

 VirtualAlloc関数に、引数MEM_RESERVE、MEM_COMMITを渡してメモリ確保を行ってみたのですが、
 メモリ確保に成功するPCと成功しないPCが存在し、理由が分からずにいます。
 (いずれもタスクマネージャなどで確認すると物理メモリの空き容量は1.3GB程度空いているPCです。)
 (確保に失敗するPCで確認してみたところ、650MB付近までは確保に成功します。)

(2) 「VirtualAlloc以外にスワップを回避して大容量のメモリを確保する方法はあるのでしょうか?」

 newでは確保ができるのですが(当然なのかもしれませんが)、
 ページングファイルに移動されてしまうと処理が重たくなってしまうので採用できない方法だと考えています。


プログラムの内容は、外部インターフェースからの入力を待つために常駐し、入力した900MB分のデータを高速に処理するというものです。
900MBのデータ量は必須で、高速かつ安価なPC構成とする必要があるために全ての処理をメモリ上で行う方法を選択しました。
ハードウェアは2GB以上のメモリを搭載、Windows XP SP3 32bitのPCに限定しています。

A 回答 (2件)

当方も最近、本題と似たような実験を行っており、質問(1)に関連した回答をさせていただきます。


(※質問(2)についてはすぐには思い当たらないため割愛いたします。)

GUIを用いるプログラムであるのならば、GUIをロードする前にメモリを確保するというのは如何でしょうか?

当方が使用しているのはC++/CLI開発環境で作る単純なGUIアプリケーションで、起動時にメイン関数を
呼んでからGUIを起動する処理と同時にメモリ1GBを確保します。
また、実験に使用したPCのスペックは3台でいずれも、メモリ:2GB、OS:Windows XP SP3です。

物理メモリの空き容量が十分にある(2GB中1.5GB)にもかかわらず、質問者がおっしゃるように
使用するPCによりメモリ確保に成功するものと失敗するものとがあるのを確認したことがあります。

そこで何故なのかを原因を探っていたところ、以下の様な違いがあることが分かりました。

(1)GUIをロード中(もしくはその後)にメモリを確保する場合:
 →失敗するPCの場合、約700MBまでしか確保できない。
  (※PCにより異なると思われる。当方が確認できたのは1台のみ。)

(2)メモリ確保をGUIロードの直前までに実行する場合:
 →メモリ確保に成功していたPCのみならず、今までに失敗していたPCでも成功。

前の回答者が述べられたとおり、成功するには確保するだけの連続したアドレス空間の空きが必要です。PCによりGUIロード時にポイントされるアドレスが同じであるとは限らず、その差異によるアドレス空間の分断がメモリ確保の成功・失敗を決めていたのではないかと考えています。

また、(2)のプログラムでVirtualAllocによるメモリ確保が最大でどれ位まで可能かも複数のPCで実験してみました。
その結果、(1)のプログラムでメモリ確保に成功のPCも失敗のPCも同じサイズ(約1.164GB)であることが分かりました。

2GB以上のメモリ搭載で32bit-OSのPCで、約900MBのメモリ確保をスワップ無しで実行できるようにするのであれば、プログラムの処理順序を変更することで本題の問題が回避できるのではないかと考えます。
    • good
    • 1
この回答へのお礼

貴重な実験結果のご報告有難うございます。とても有用な手法だと思います。
GUIのロードを行う順番による解決は思い至りませんでした。
参考にさせていただき実装方法を検討してみたいと思います。

私の方でもVirtualAllocによる最大確保可能な連続仮想アドレス容量がどの程度あるか、以下の3条件で実験してみました。
いずれもVisualStudio2008で空のプロジェクトを作成した後、main関数に入った直後にVirtualAllocで連続確保可能な容量を調べるようコードを追加しています。

PCのスペックは「メモリ:2GB、OS:WindowsXP SP3 32Bit」、
メモリの大量確保に失敗するPC1台です。結果、以下の通りとなりました。
(拙い知識での実験で問題点も多いかと思いますがご容赦ください。)

(1)Win32コンソールアプリケーション:1920MB
(2)CLRコンソールアプリケーション(.NET Freamwork 3.5):1403MB
(3)Windowsフォームアプリケーション(.NET Freamwork 3.5):767MB

上記結果からも推測するに、
evaWK0様にご教示頂いた通りの現象が起きている蓋然性が高いと私も考えます。
ご回答有難う御座いました。

お礼日時:2010/10/12 21:16

まず、VirtualAllocは仮想アドレス空間を確保するだけでスワップアウト禁止にはしてくれません。

スワップアウトを禁止するにはVirtualLockを併用する必要がありますが、これでロックできるメモリ量は標準では非常に小さいので、ワーキングセットを拡大する設定を行う必要があります。
ただし、過大なメモリをスワップアウト禁止にするとシステムが不安定になる可能性があるのでお奨めしません。

(1)
上に書いたようにVirtualAllocは仮想アドレス空間を確保します。成功するには確保するだけの連続したアドレス空間の空きが必要です。32bitアプリケーションのユーザーアドレス空間2GBに対して900MBはけっこう大きいので、先に呼んだVirtualAllocやリンクされたDLLなどでアドレス空間が分断されると確保に失敗する可能性が生じます。
実行するPCによって結果が異なるということだと標準ライブラリDLLのバージョン違いでリンクアドレスかサイズが異なっているという可能性が考えられます。

(2)
プログラムでメモリ空間をスワップアウト禁止するには最初に書いたようにVirtualLockがあります。
他の手法としては、
1.ページファイルサイズを0にしてスワップアウト先を無くす。
2.十分なメモリを用意してスワップアウトされないことに賭ける。
くらいが思いつくところです。
    • good
    • 0
この回答へのお礼

詳細なご回答有難うございます。
スアップアウウト禁止にVirtualLockを併用しなければならない点、ご指摘の通りでした。
プログラムを見直したところ、事前にVirtualAllocで予約、使用する際にはVirturalLockを使用するといった方法をとっています。

(1)のご回答について
ご指摘の通りドライバ関係で呼んでいるDLL上等にVirtualAllocやVirtualLockが使われている可能性があるかもしれません。
また、SDKのバージョンなどはなるべく揃えていますが、リンクアドレスやサイズが変わってしまうという可能性には気づきませんでした。

(2)のご回答について
やはり具体的手法としてはVirtualLockが最も現実的ですね。
環境に依存せず確実に確保できるタイミングを探してみようかと思います。

環境によってプロセスのメモリ使用状況がどう異なるのか、仮想アドレスの予約状況をVirtualQueryを利用して、ログで出力するようなクラスを作成し、ところどころメモリの使用状況をチェックしてみようかと思います。
また、C&C++という前提でしたが、CLIも組み込まれているようなので、その点がメモリ管理に影響している可能性があると踏んでいます(質問の前提条件に挙がってない事実でした。すみません。。。)

お礼日時:2009/12/02 10:01

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!