大きな配列を渡そうとする場合

[戻る]
Tj 2002/10/08(火) 20:02:46
float  A[128*128*10*30];
と言うような大きな配列を関数で渡そうとする場合、
関数(Func)での受けとしては
Func(float  *FA, , , , )  /* FAがAそのものを表す引数 */
{

}
だと思うのですが、
Mainから出す側としては、
Func(A, , , ,);
の記述でいいのでしょうか?
それとも
Func(*A, , , ,)
でいいのでしょうか?

またこのような大きな配列を持つ変数を多く使うので
リンク中
LNK4084: トータル イメージ サイズ 1804898304 が最大値 (268435456) を越えています
が出て実行できなくなっているので、
メモリの節約に行くのですが、大幅には、使用メモリは減りません。
そう言うところに気をつければバッサリ減らせるのでしょうか?

n [E-Mail] 2002/10/08(火) 22:32:31
new や malloc は試してみた?
使い方はこう( malloc の場合):

void Func( float* a, const int size )
{
 int i;
 for ( i = 0; i < size; i++ ) {
  a[ i ] = ( float )i;
 }
}

void foo()
{
 float* pa = 0;
 const int NUMBER_OF_ELEMENTS = 128*128*10*30;
 const int ALLOCATE_SIZE = sizeof( float ) * NUMBER_OF_ELEMENTS;

 /* 確保 */
 pa = ( float* )malloc( ALLOCATE_SIZE );

 /* 使用 */
 Func( pa, NUMBER_OF_ELEMENTS );

 /* 使い終わったら必ず開放する */
 free( pa );
}

Tj 2002/10/08(火) 23:22:42
ありがとうございます。

今のきなみMALLOC、 FREEがらみに
置き換えているところです。

私の2つあるうちの最初の質問は
Mainから出す側としては、
Func(A, , , ,);
の記述でいいのですよね。

アイススケーター 2002/10/09(水) 05:54:28
↓でOKです。
>Func(A, , , ,);

ただ、このへんの質問があるということは、ポインタを勉強されたほうが
良いと思います。

Tj 2002/10/09(水) 12:39:13
辛言ありがとうございます。

なんとか、全部大きな配列型の変数をMALLOCとFREEに
変えて、この問題を消せたようです。

時に、
A = (int *) malloc(100 * 256 * 256  * 200 * sizeof(int));
や
B = (float *) malloc(100 * 256 * 256  * 200 * sizeof(float));
と言う変数のエリアを確保出来ているかどうか調べたいのですが、
これは単純に
if (A == NULL)
とか
if (B == NULL)
と聞けばよいのでしょうか?

アイススケーター 2002/10/09(水) 13:00:26
if (A == NULL)
{
   // 確保できなかった場合の処理   
}

でOKです。

mallocは
  「使えるメモリが足りないときはNULLを返す」とあります。

開発環境にVCがあればHELP→キーワード検索で参照できますよ。

Tj 2002/10/09(水) 17:00:53
じょじょにMALLOC値がNULLでないかどうかでメモリが確保出来ているかどうかを
確かめて行っていますが、
A = (int *) malloc(100 * 256 * 512  * 200 * sizeof(int));
というようなものを確保しようとする場合、
使った後でFREEしようがしまいが、
占有に1GByteを超えてしまっているので、
メモリ確保は出来ないのですが、
このような時、うまい圧縮なんかはできないものなのでしょうか?
A = (int *) malloc(128 * 256 * 512  * 256 * sizeof(int));
とした場合でも同じでしょうか?

Tj 2002/10/09(水) 17:59:18
あと、もう一つお願いします。
malloc内の数値が小さいケースはわかるのですが、

    S = (float *) malloc(256 * 256 * 256 * 256 * 30 * sizeof(float));
    if (S == NULL)
    {
        printf("メモリ確保出来ず ! \n");
        exit(10);
    }    

ってやったら、なんと、NULLにならず通りぬけて行きました。
120GByteなのに。
信じていいのかな。
(だって、物理的に256MB程度しか積んでないはずなのに。
 何か裏技でもシステムがやってるのかな)

それと、やはり確保で時間がかかりすぎ。
30秒〜1分くらいかかっていた。
もっと時間をちじめる設定って出来ないのでしょうか?

ちなみに私のところはWINDOWSモードのVC++6です。

アイススケーター 2002/10/09(水) 18:48:15
何をしたくてこのようなメモリを利用するのか私には理解できないのですが、
根本的にこのようなサイズを使用するようなアプリケーションはあるのですか。

ちなみに

>    S = (float *) malloc(256 * 256 * 256 * 256 * 30 * sizeof(float));
mallocの引数は(size_t unsigned int)なので上記のデータは0となります。
>    if (S == NULL)
サイズが0のためSはNULLとはなりません
>    {
>        printf("メモリ確保出来ず ! \n");
>        exit(10);
>    }

wood 2002/10/09(水) 19:12:47
回答ではありません

>ちなみに私のところはWINDOWSモードのVC++6です。
VMウェアを使っているということでしょうか?
Windowsが物理メモリ以上の確保が出来るのはメモリをスワップファイルへ確保するためです
ディスクアクセスを行うため時間が掛るのでしょう

95・98は一度に確保できる最大メモリは理論上2GBだったはずです
NTや2000の場合は理論上2GB以上の確保が出来たはずですが
実際に試したことは無いです

仮想メモリが使われますのでディスクの容量には十分注意してください
最悪起動しなくなることがありますよ

Tj 2002/10/09(水) 19:47:06
うちは95でのVC++6で使っています。

確認ですが、
メモリが確保されなかった場合は
S = (float *) malloc(256 * 256 * 256 * 256 * 30 * sizeof(float));
の値がNULLで出るということで間違いないですね。
アプリは画像・音声一杯あります。
何故なら、別な変数で
A = (int *) malloc(100 * 256 * 256  * 200 * sizeof(int));
の場合NULLが帰って来て、
A = (int *) malloc(100 * 10 * 256  * 200 * sizeof(int));
にすると帰らなくなりました。

A = (int *) malloc(100 * 256 * 256  * 200 * sizeof(int));
でメモリ確保出来ずと思われるNULLが帰っていたのにのに、
それよりかなりエリアが大きいじゃないかと思われる
CepEachS = (float *) malloc(256 * 256 * 256 * 256 * 30 * sizeof(float));
で帰っていないですね。 
(ポインターはintで1バイトずつ、floatで4バイトずつ、doubleで8バイトずつ
 進むと言う理解でいいですね。)

いずれにしても仮想メモリが使われるということは、
値としてちゃんと入って来なくなる可能性はありますか?

ともかくアクセスのスピードを何とかして早くしなければ、と思っています。

Tj 2002/10/09(水) 20:00:56
でもやっぱりおかしいのかなあ。
256 * 256 * 256 * 256 * 30 * sizeof(float)
を計算すると、515Gバイト。
仮想であろうと何であろうと、
これだけのメモリが確保されるのでしょうか?
CepEachS = (float *) malloc(256 * 256 * 256 * 256 * 30 * sizeof(float));
勿論、上記CepEachSと言う変数はNULLでも0でもなっていない訳ですが、
他にメモリが確保されたかどうかの確認の仕方はあるのでしょうか?

アイススケーター 2002/10/09(水) 20:06:18
>A = (int *) malloc(100 * 256 * 256  * 200 * sizeof(int));
>の場合NULLが帰って来て、

この場合、実際にメモリが確保(5GB→実際は1GB)できなくてNULLに
なったものと思われます。

何度も言いますが、mallocの引数は(size_t unsigned int)のため指定できるのは
4GBまでです。

>A = (int *) malloc(100 * 10 * 256  * 200 * sizeof(int));
>にすると帰らなくなりました。

この場合はメモリ確保が200MBなので一生懸命OSが確保しようとしているのでは・・・

Tjさんのマシンはどの程度メモリをつんでいるんですか。
ちなみに画像・音声の処理も一度に全部のデータをメモリ上にロードしているアプリは
ないんじゃないですか。ほとんどのアプリはハードディスクを利用していると思いますが。

Tj 2002/10/09(水) 20:29:37
なるほど。
アイススケーターさん。
うちは物理メモリは256MBですね。
でも
A = (int *) malloc(100 * 256 * 256  * 200 * sizeof(int));
が嫌われて、もっとエリアとしては大きいはずの
S = (float *) malloc(256 * 256 * 256 * 256 * 30 * sizeof(float));
が蹴られてないというのも不思議なんですが。

アイススケーター 2002/10/09(水) 20:40:26
もう一度計算してみてください。

unsigned intは0x00000000〜0xffffffffまでです。

>A = (int *) malloc(100 * 256 * 256  * 200 * sizeof(int));
>が嫌われて、もっとエリアとしては大きいはずの

この値は、mallocには5GBではなく1GBとして渡されます。
5GBを0xffffffffでANDしてみると解ります

5GBは0x140000000ですがこれに0xffffffffをANDすると
    0x040000000(1GB)となります。

>S = (float *) malloc(256 * 256 * 256 * 256 * 30 * sizeof(float));

この値は、0xf000000000(960GB)ですがこれに0xffffffffをANDすると
     0x0000000000(0バイト)となります。
このため、こちらは正常応答となっています。

コンピュータの、データ範囲をしっかり頭に入れておきましょう。

アイススケーター 2002/10/09(水) 20:43:19
ちなみに私のマシンは
 メモリ 192MB
 Windows2000
ですが
200MBのエリアを試しに確保しましたが、数分かかりました。
この間、ハードディスクのアクセスランプがつきっぱなしでした。
もう二度とこんなことはしないぞ。

アイススケーター 2002/10/09(水) 20:47:07
追伸

先ほどのテスト後、マシンのレスポンスが遅くなりました。
このため、再立ち上げを行いました。

よい子のみんなはマネしないように。

kazuma 2002/10/10(木) 00:12:48
> アプリは画像・音声一杯あります。

当面必要なものだけメモリ上に置いておいて、
残りはファイルなどに置いておくといった工夫をするのが普通だと思いますが。

Tj 2002/10/10(木) 00:53:04
勉強不足ですみません。

>この値は、mallocには5GBではなく1GBとして渡されます。
>5GBを0xffffffffでANDしてみると解ります

>5GBは0x140000000ですがこれに0xffffffffをANDすると
>0x040000000(1GB)となります。

なんでUNSIGNED INTの時は
0xffffffffでANDしないと
いけないのでしょうか?

Tj 2002/10/10(木) 00:58:09
>この値は、0xf000000000(960GB)ですがこれに0xffffffffをANDすると
>0x0000000000(0バイト)となります。
>このため、こちらは正常応答となっています。

正常応答と言っても、
エリアとしては確保できていないのですね。
ここでは

YuO [E-Mail] 2002/10/10(木) 01:25:26
> なんでUNSIGNED INTの時は
> 0xffffffffでANDしないと
> いけないのでしょうか?

うんにゃ。単純にオーバーフローしているだけの話。

変数に格納されるのは,オーバーフローして0xFFFFFFFFとの論理積になるということを,
アイススケーターさんは言いたいのだと思います。

次のプログラムを実行してみてください。

#include <stdio.h>

int main (void)
{
    size_t size = 100 * 256 * 256  * 200 * sizeof(int);
    printf("%x\n", size);
    return 0;
}

Tjさんが予期しているはずの138800000ではなく,38800000が表示されるはずです。

アイススケーター 2002/10/10(木) 06:18:32
YuOさん代弁ありがとうございました。

データの範囲はWindowsの場合は

    char            -   0x80  〜       0x7f 
    BYTE                   0  〜       0xff
    short           - 0x8000  〜    0x7fff
    WORD                   0  〜     0xffff
    int(long)     -0x8000000  〜 0x7fffffff
    unsigned int           0  〜 0xffffffff
     ※int は別システムではshortと同じ範囲となる場合もある。

です。
計算値がオーバーフローすると計算結果でオーバーフローした上位分を切り捨てます。

↓YuOさんが書いてくださった分
>#include <stdio.h>

>int main (void)
>{
>    size_t size = 100 * 256 * 256  * 200 * sizeof(int);
>    printf("%x\n", size);
>    return 0;
>}

>Tjさんが予期しているはずの138800000ではなく,38800000が表示されるはずです。

100 * 256 * 256  * 200 * sizeof(int) -> 0x138800000
                                           ~--------
↑の~部分がオーバーフローした上位分です。
C言語は、オーバーフローした分をエラーとして返さないためプログラマはこれを意識
してプログラムする必要があります。
アセンブラならオーバーフローしたときにフラグが立つのですが、ここでは関係ないので
あまり触れないようにします。

ここまで書いて、解らない場合は、もうめんどうみきれません。

さようなら

Tj 2002/10/10(木) 06:49:56
なるほど。
よくわかりました。

変数がふくらんだので、今後は
かなりの分、
ファイルをFOPENしてFPUTしていこうと思います。

Tj 2002/10/10(木) 21:27:03
[[解決]]
解決です。

古いスレッドには追加発言できません。