よろしくお願いします。
環境:WindowsXP(32ビット)で、VC++6.0
PCは4Gのメモリ搭載していて、
プログラム上で、1.5Gのメモリを取得したいのですが、
うまくいきません。mallocで、NULLが返されます。
何かよい方法などございましたら、ご教授よろしくお願いいたします。
windows タスクマネージャで、利用可能な物理メモリは
プログラム起動中、2.6G以上あります。
Win32 では、1つのプロセスあたりの仮想メモリ空間が 2GB に制約されています。
プログラムサイズを小さくするとかすれば 1.5GB の作業空間を確保することが
可能になるかもしれませんが、なんともいえないぎりぎりのところです。
Win64 に移行するのが適切でしょう。
terapod様
ご教授ありがとうございます。
調べてみたのですが、WIN64に移行した際
1つのプロセスあたりの仮想メモリ空間は
8TBになると記述をみたのですが、ただ
32ビットアプリケーションですと、
4GBの仮想メモリに自動的にアドレス指定できるとありました。
win32ー>win64にした際、VC++6.0でプログラム実装をしていく際
に使用できる仮想メモリ空間は、2G->4Gになるという結論でよろしい
のでしょうか。
大変申し訳ありませんが、ご教授の程、よろしくお願いいたします。
いいえ。 2GB のままです。
・「/LARGEADDRESSAWARE を指定してコンパイルした場合」のみ 4GB を使える
・VC++6 は /LARGEADDRESSAWARE は非対応
ですから。
ちょっと気になったのですが 1.5GB の「連続領域」が必要なのですか?
malloc(1.5GB) がしたい?それとも malloc(1MB)*1536 で無問題?
後者なら普通に Win32 でできてもおかしくないような気がします。
ちょっと特殊な要望がない限り前者の必然ってのが考えにくいのですけど。
tetrapod 様
ご返信ありがとうございます。
1.5GBの領域ですが、後者のように分割してメモリ取得できれば、
OKなのですが
いろいろ試してみて(後者のやり方にちかい形でも、検証もしました)、
1.5Gの領域が取得できませんでした。
そのほかに、既に750Mの領域を確保しています。
malloc(1MB)*1536ですと、処理の合間でメモリ開放もされている
と仮定されているのでしょうか。
私自身、こんなに大量のメモリを使用して、プログラム実装を
した事がないため、見当違いの発言をしていたら、すいません。
メモリ取得できなければ、ソフトの実装方法を考え直した方が、
いいのかと考えております。
>そのほかに、既に750Mの領域を確保しています。
って 1.5G+750M だと 2GB を超えてますけど。
実験してみればわかりますが 1MB を malloc すると、アドレス空間を 1.06MB 食います。
1MB-64 にすると 1.00MB の消費で済みます。
まあどっちにせよ「無理」ですね。
1GB というと、ふた昔前のハードディスクの容量よりでかいわけですし
速度が必要ないのならオンメモリで処理しないのが普通でしょう。
なんとしてでもオンメモリで処理する必要があるなら再考慮。
新しいコンパイラを採用するとか、 64bit な Windows/UNIX を使うとか。
まず、そのプログラムで1.5Gのメモリ確保してるコードをコメントアウト
した状態で動かしてみて、メモリ使用量がどの程度なのか提示して欲しい
と思います。
プログラムサイズが小さくてもスタックサイズの大小やGUI使用の有無でも
だいぶ変わってくる話なので・・
>1.5Gの領域が取得できませんでした。
>そのほかに、既に750Mの領域を確保しています。
これはどう言う意味ですか?
1.1.5Gは確保出来なかったが、750M は確保出来た。
2.そのプロセスが、750Mの領域を既に確保している状態で、更に1.5Gを
確保したい。
3.そのプロセス以外のプロセスが 750M の領域を確保している。
文面通りだと 2番の意味に見えますが・・・
何でmalloc?
物理メモリから取得しなくても、仮想メモリから取得すれば?
VirtualAlloc
とか・・・
http://www.microsoft.com/japan/developer/library/jpwinpf/_win32_virtualalloc.htm
参考までに
以上。
いえ、この場合 VirtualAlloc は全く無意味。
Win32 の「1プロセスの仮想メモリ空間が2GB」であるため
VirtualAlloc を使おうが malloc を使おうが
1プロセスで 2GB 超のメモリを使うことはできません。
# ぬるぽチェック領域とか、ありとあらゆる領域の総和が 2GB 以下ということ。
# 作業領域に使える仮想メモリ空間が 1.5GB 以下ってのはごくふつうにありそう。
ご返信ありがとうございます。
tetrapod 様
速度が、必要なのでオンメモリで処理しなければなりません。
もう一度、再検討してみます。
Toshi 様
■1.5Gのメモリ確保してるコードをコメントアウトした状態で
プログラムをうごかして、
※windows タスクマネージャの、利用可能な物理メモリで調べたところ、
メモリ使用率1Gです。
やりたいことは、
-------------
・750Mの領域を既に確保している状態で、更に1.5Gを確保したいです。
---------------------------------------------------------------------
今まで、ご教授いただいた事
----------------
1.Win32 では、1つのプロセスあたりの仮想メモリ空間が 2GB の制約な ので、無理。
2.windows professional x64 editionに変更しても、
VC++6.0は、LARGEADDRESSAWARE を指定してコンパイルは未対応のため
無理
>※windows タスクマネージャの、利用可能な物理メモリで調べたところ、
> メモリ使用率1Gです。
知りたかったのは、
タスクマネージャ→プロセスで見れる「メモリ使用量」で確認出来る、
そのプロセスが使用しているメモリなのですが・・
それが 1Gだと言う事ですか?
そして、それは 750M の確保込みで 1Gって事ですね?
でもって、更に、1.5G 確保したいと言う事ですね?
結論ですが、32bit環境では既に既知の通り「無理」です。
で、VC 6.0 に64bit版は確か無かったと思います。
逆に言えば、VC 6.0 で64bitアプリを開発する際は、
PlatformSDK を使う必要が有り、VC 6.0 + PlatformSDK のクロスコンパイラ
環境が、VC 6.0 の 64bit開発環境と言えます。
で、64bitコードを吐き出すリンカは platformSDK付属の物を使いますが、
こいつには「LARGEADDRESSAWARE」が使えますので問題ありません。
但し、これはあくまで「2G以上の空間を使う事を宣言」するだけで、
「4Gまで使える」と言う事では有りません。
実際は、3G程度使えると考えておけば良さそうです。
ですので、1G + 1.5G なら64bit化でいけます。
補足です。
「いけます」なんて断言しちゃいけませんね。
「いける理屈になります」と訂正しときます。
それと、VC 6.0 + platformSDK は、実質の所 .NET にするのと同程度、
プリプロの仕様が変わります。(特に64bit環境では)
どうせなら、 VC++ .NET系に移行される事をお勧めします。
ご返信ありがとうございます。
皆様
ご教授いただいた内容を参考にさせていただきます。
ありがとうございました。
>メモリ取得できなければ、ソフトの実装方法を考え直した方が、
とりあえず解決されたようですが、蛇足を承知で別のアイデアを…
あるデータを処理する場合、普通「局所性」がありますので、例え2Gのデータであっても、ある時点で処理しているのは100MBも無い可能性が非常に高いです。そこで100MBのバッファを2,3個確保してダブルバッファやトリプルバッファとし、メインのバッファで計算や解析をしている間にサブのバッファに次に必要とされるデータをHDDから読み込みます。
イメージとしてはCPUのキャッシュメモリの仕組みをアプリケーションの中でエミュレーションして再現する感じですね。これなら対象データが5Gや10Gに増えても「ほぼオンメモリと同じ速度」で動作する可能性が高いですので、有益だと思われます。
プログラム的にも作るのが面白そうですし、もしひろさんがプログラマーとしての実力アップを望んでいるならそういうアプローチも良さそうです。
逆にあくまでプログラムは道具に過ぎず、データの処理自体が目的なら64Bit環境に移行するのが良さそうですけどね。まあ蛇足と言うことで^^;
解決されたようなので・・・
ですが、何故、不可能なの?
一個のプロセス空間で制限があるのは既知の通りですが・・・
では、複数のプロセス空間でメモリマネジメントさせるような
仕組みは考えられないのでしょうか?
私は実現しましたがネ〜
1個のプロセスに固執する意味は、技術的には超えられるし・・・
ただ実現性や安全性・システムの安定性を考えれば、そのような
膨大なメモリを必要とするもの自体が問題と言う原点に返ってくる
とは思いますが・・・
オラクルのデータベースエンジンは、複数のインスタンスで実現する
ようになっていますし、SQL Serverも複数インスタンスでより巨大な
データベースを運用可能になってきています。
同じことではないのでしょうか?
まぁ〜いいけど・・・
以上。
640MB さんの案に加えて、データの書き出す先を、物理的なHDDでは動作が遅くなるので、
RAMディスクを用意して、そこを使うのはどうだろうか?
これなら、スワップ(と呼べばいいのかな)の際の読み書きも、だいぶ高速化できるのでは?
AWE(Address Windowing Extension)なんぞ使ってみてはいかがでしょう。
一度に使えるのは2GBまでですが、物理メモリがもっとあるのなら、数GBの領域を予約しておいて、それを2GBずつ使うことができます。
加えて、常に仮想メモリではなく物理メモリに確保されることが保障されるので、速度的にもバッチリです。
唯一の弱点は、特権が必要なことですが…
メモリマップトファイルじゃだめなんでしょうか。
MS-DOS時代にやりました。
巨大な配列がメモリ上にあるかのように見せかけるvirtual-arrayてやつ。
中身はキャッシュとランダムアクセスファイルなんだけど (^^
template<typename T>
class virtual_array {
public:
virtual_array(std::string path, unsigned cache_size);
const T& operator[](unsigned long);
…どーのこーの
};
余談です。
メモリ管理に関して色々なアイデアが出ていますが、
業務をする上で、時間と金さえ有ればソフト的に
大抵の事は出来ると思ってます。
結局はメモリマネージの仕掛けを作りこむ工数を
ゲット出来るかどうかが大抵の場合問題になるでしょう。
今のITの景気を見る限り、どこも予算は絞ってるはずなので、
最終的には「一番すっきりする方法」では無く、
「一番早く安上がりで実績が有りメンテ性が有利な方法」で
落ち着くのが常なんじゃないかと思います。
なので、「テクニカルに走れば出来るじゃん!」と余り強く
言うのも酷な様な気が・・・
知ったかが多いな
#何のつもりで一年前のスレを上げたのかわかりませんが、
#せっかくなので一点訂正。
> 知りたかったのは、
> タスクマネージャ→プロセスで見れる「メモリ使用量」で確認出来る、
> そのプロセスが使用しているメモリなのですが・・
「メモリ使用量」の値は「ワーキングセット」と呼ばれる、そのプロセスが物理メモリに確保している領域のサイズです。
これは、プログラムが迅速に反応できるように物理メモリにキャッシュされているものであって、ページングファイルにスワップされると減ります。
そのプロセスが本当に使っているメモリ領域のサイズは、「仮想メモリサイズ」という列に表示されます。
誰だよ!俺が昔書いたのとそっくりなアイデアを書いている奴は?
俺のコピペか?と思ったら自分の書き込みだった^^;
しかし1年前の書き込みを見るのもちょっと楽しいですな。
ツイート | ![]() |