- ベストアンサー
グローバル変数とメモリについて
質問させてもらいます。 #include <stdio.h> #include <math.h> #include M 1000 double a[M][M]; のようにプログラム冒頭にグローバル変数として配列aを宣言しているのですが、windowsXPではMを4096以上にして保存し、コンパイル(BCC)すると Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland beki4.c: Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland Fatal: Error detected (LME1514) Fatal: Error detected (LME1514) Fatal: Error detected (LME1514) Fatal: Error detected (LME1514) と出て、コンパイルができません。4095では可能でした。 最初はメモリの不足かと思ったのですが、単純に計算すると4096*4096*8 byteで、この配列には約134MB程度しかかかりません。メインメモリが1GBでその他OSなどが消費しているメモリは500MB程度なのでメモリ不足では無いような気がします。 同じプログラムをfedora8でメインメモリ1GBのPCでやらせてみた所、M=16383まではコンパイル(gcc)でき、16384以上では「too large」と言われてコンパイルできませんでした。 それぞれのOSでのMの設定値の限界が4095(=2^12-1),16383(=2^14-1)となっていまして、これはそれぞれのOSで一つの変数が占有できるメモリの限界を定めているということを意味しているのでしょうか? またこのような限度がOSにあった場合、その設定を変更する方法はありますか? よろしくお願いします。 実際のプログラム→http://cocofox.konjiki.jp/beki.html(文字数制限の関係上ここにすべてのcodeを記載できないため)
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
★アドバイス ・Windows では仮想メモリの上限が2ギガ・バイトまでです。 でも実際には物理メモリ量やスタックその他で2ギガ・バイトは使えません。 こちらの環境では M=4096 はもちろん M=16367 までコンパイルできました。 ただし M=16367 では実行時にエラーになりました。 (物理メモリが足りないので当然ですが…) ・こちらの環境は Windows XP Home SP2、RAM=768MB です。 コンパイラは VC++2003.NET でコンソール・アプリケーションとして試しました。 M=4096 まではコンパイル、実行時のエラーもありませんでした。 >単純に計算すると4096*4096*8 byteで、この配列には約134MB程度しかかかりません。 ↑ 計算が間違っています。 4096*4096*8=134,217,728=128MBです。 ※1024 で割りましょう。 BCCは使ったことがありませんが、もしかしたらコンパイラの設定の違いでしょうか? ・以上。
その他の回答 (5)
- jacta
- ベストアンサー率26% (845/3158)
何となくリンカの問題のような気がします。 というのも、M=4096ではエラーが発生しますが.exeは生成され、実行もできます。M=5287まではそうした状況が続きます。M=5288以上になると.exeが生成されなくなり、エラーメッセージがおかしくなります。 M=5709以上になると、 Fatal: Out of memory というエラーメッセージに変わります。 一応C90で保証されるオブジェクトのバイト数は32767バイトまでですので、Mが大きくなると規格上は保証がなくなります。結果として未定義の動作に至ったとしても、一概にリンカの不具合とまではいえません。 ただ、不親切なことは確かですね。
お礼
回答ありがとうございます。 返答に時間がかかってしまい申し訳ありませんでした。 現状の結果としては質問しました問題は解決できていないのですが、別の形で十分な量の実験データをとることができましたので、これで今回は質問を閉じたいと思います。アドバイスを下さった皆様、本当にありがとうございました。
- Oh-Orange
- ベストアンサー率63% (854/1345)
★追記。 ・VirtualAlloc() 関数を使ったらどのぐらい確保できますか? 下のサンプルでは 128 MBのメモリを確保します。 試して見て下さい。 (もし、確保できればコンパイラの設定か、コンパイラが原因かもしれない) #include <stdio.h> #include <windows.h> // メイン関数 int main( void ) { SIZE_T dwSize = 128 * 1024 * 1024; // 128MB LPTSTR lpBuff; if ( (lpBuff = (LPTSTR)VirtualAlloc(NULL,dwSize,MEM_COMMIT,PAGE_READWRITE | PAGE_NOCACHE)) != NULL ){ ZeroMemory( lpBuff, dwSize ); VirtualFree( lpBuff, dwSize, MEM_RELEASE ); } return 0; }
補足
ありがとうございます。頂いたサンプルですが正直ぜんぜん内容が分からないので、何をもってメモリが確保できたとわかるのか分からないのですが、実行することはできました。加えて、タスクマネージャを使ってメモリの消費を見ていると、実行した瞬間に120MBくらい消費が増加するのが確認できました。(一瞬なので細かい増加量はわかりませんorz) 確保できたとなるとやはりコンパイラの設定が問題なのかもしれません。
- aris-wiz
- ベストアンサー率38% (96/252)
>グローバル変数 そですね。。。スタティック領域なので、 スタックは関係なさそうですorz
- a-saitoh
- ベストアンサー率30% (524/1722)
グローバル変数ですのでスタック領域ではなくてデータセグメント(明示的な初期化が無いのでBSS)の大きさの制限だとおもいます。 手元にBCCが無いので確認できないのですが、コンパイラの設定で拡大できると思います。 OSの制限なら、リンクは成功して実行するときにエラーになっているはずです。
お礼
ご回答ありがとうございます。OSではなくコンパイラの設定の問題ですか、helpなどになにかないか見てみます。
- aris-wiz
- ベストアンサー率38% (96/252)
>またこのような限度がOSにあった場合、 >その設定を変更する方法はありますか? OSではなくコンパイラにスタックサイズの制限があります。 BCC/VCなどはデフォルト1Mくらいだったかと。 32Bit環境としてdouble=8バイト 8*1000*1000バイトでオーバーですね。 過去ログ http://oshiete1.goo.ne.jp/qa2487531.html
お礼
ご回答ありがとうございます。リンク先参考になりました。
お礼
ご回答ありがとうございます。たしかに1000でなく1024で割るべきでした、指摘ありがとうございます。