動的メモリの上限について

[戻る]
大三元 2006/06/22(木) 11:20:45
くだらない質問かも知れませんが教えて頂きたいです。

CArrayやCStringなどで宣言すると動的にエリアを確保すると思いますが、
その上限はどのぐらいまで有効なのでしょうか?
環境や、PCのメモリサイズにもよると思いますが・・・
3Mぐらいは余裕ですかね?

PATIO 2006/06/22(木) 11:50:48
別のスレッドで話題になった事があったと思いますけれど、
通常、一つのプロセスは2GBがメモリアクセスができる上限だったともいます。
但し、実際にヒープ領域として使用できるのはそこまで大きな領域には
ならないはずです。プログラムやOSが動作する為に使用する領域も2GBに含まれて
いたと思います。
実際にはPCの搭載しているメモリの量に寄りますね。
実際にはスワップファイルを用いて実搭載している物理メモリ以上の容量が
使えますけれど、スワップが発生するとパフォーマンスが急激に落ちますので
実際にはスワップが発生しない程度に抑えないと使い辛いソフトになると思います。
この辺は必要動作環境をどの程度に設定するかと言うアプリの設計にも寄ります。
考え所でしょう。

PATIO 2006/06/22(木) 11:52:56
ああ、前提条件を忘れてました。
Win32の環境であればと言う但し書きがつきます。
Win64だともっと大容量のメモリが扱えるようになります。
この辺はご自分で調べて見てください。
Webを検索するれば、結構引っかかると思います。

大三元 2006/06/22(木) 11:55:36
内容が不十分のため、補足します。

何がやりたいのかというと、

typedef struct{
    15byte
}; KATA

15バイトのデータを持つ情報が最大16000の配列分ある。
CArray<KATA,KATA>m_def;
WORD m_defNum;   // 最大16000ぐらい

このなかである条件を満たした情報のインデックスを次のm_1に保存していく。
m_1の情報の中でさらに、
ある条件を満たすもののm_defのインデックスをm_2に保存していく。
これを最大m_5まで行なう。

CArray<WORD,WORD>m_1;  // m_defのインデックス
CArray<WORD,WORD>m_2;
CArray<WORD,WORD>m_3;
CArray<WORD,WORD>m_4;
CArray<WORD,WORD>m_5;

しかし、もしメモリが余裕ならば、
CArray<KATA,KATA>m_1;
CArray<KATA,KATA>m_2;
CArray<KATA,KATA>m_3;
CArray<KATA,KATA>m_4;
CArray<KATA,KATA>m_5;
このようにそれぞれで情報をもったほうが
メモリは無駄になるが、
処理が早くなる。
判定など必要なくなる。
なので、
できれば後者のほうがいいと思うのですが
どうでしょうか?

大三元 2006/06/22(木) 12:05:51
計算すると、
m_defの情報全てが条件に満たしたとして(m_1〜m_5)
前者だと1.44Mで後者は400Kになりました。
そのほかにも動的に確保しているものもあるので、
多くみつもっても3Mぐらい使用するかな?ということです。

最近のPCはほとんど512M以上のメモリがあると思うので
このぐらいのサイズなら余裕かな?
と、思うのですがいかがなものでしょうか?
みなさんの見解を聞きたいです。

PATIO 2006/06/22(木) 12:08:22
m_1、m_2、m_3、m_4、m_5に重複した物が入らないのであれば
最初にデータを振り分けてしまえば最初のm_defはいらないのではとも思いますが、
多分、私ならやりません。
データの二重管理になるので両方の整合性とかメモリの無駄とか考えたら
あまり良い方法とは思えないからです。
また、インデックスを保持する方法でもそこまで遅くなるとは思えないんですが、
実際に実験してみましたか?
その差は無視できないほど大きな差になったでしょうか?

CArrayはリリース版とデバッグ版では全くスピードが違いますから
パフォーマンスを見るのでしたらリリース版で確認しないと駄目ですよ。

大三元 2006/06/22(木) 13:11:06
>m_1、m_2、m_3、m_4、m_5に重複した物が入らないのであれば
>最初にデータを振り分けてしまえば最初のm_defはいらないのではとも思いますが
m_defの内容は必要です。
m_defの内容の中で検索条件Aにひっかかるものをm_1に登録。
m_1の内容の中で検索条件Bにひっかかるものをm_2に登録。
そのときの検索内容をリストコントロールに書き込みます。(検索前はm_defの内容全て)
また、デフォルトボタン押下時は、m_1〜m_5の内容は削除します。(RemoveAll)
検索条件のトリガは5つほどあるので重複することは普通にあります。
また、m_3→m_2と戻ることはありません。
別の検索方法で内容を絞りたいときは【デフォルト】ボタンを押します。
また、検索条件はアプリ実行者が選択するものであらかじめ決まっているもの
ではありません。

>また、インデックスを保持する方法でもそこまで遅くなるとは思えないんですが、
>実際に実験してみましたか?
してないです。
その部分はこれからコーティングするんですけど、
インデックスを保持する方法よりそれぞれデータ保持するほうが
プログラム的にも判定が少なく美しいと思ったからです。

大三元 2006/06/22(木) 14:16:17
今思いついたのですが、
CArray<KATA,KATA>m_def;
CArray<WORD,WORD>m_1;
の型が異なるために余計な判定や
設計に苦労してます。

よって、
CArray<WORD,WORD>m_0;
というのを宣言しておいて
m_defの要素に追加する時に同時に
同じインデックスを初めから設定しておけば
型が同じになるので設計も楽になります。
領域が無駄にひとつ増えますが、
こんなことで悩むぐらいならいいかと・・

自分としてはメモリ領域に余裕があるなら
無駄な領域を確保しても
それでプログラムが美しく、
設計しやすくなるなら
そのほうがよいと考えています。

どうでしょうか?

ねこたま 2006/06/22(木) 14:37:35
美しいとかはとりあえず置いておいて、何がしたいのかよくわからないとこですが、
CArrayの使いかたからしてどう問題なのかな?と

ちなみに私はインデックス保持派っすね
やっぱ同じデータを複数作成するってのはどうも。。。

で、そうすると参照時は
for(int i=0;i<m_1.GetCount();i++){
  hoge = m_def[m_1[i]].m_hoge;
}
ですよね?

インデックス登録時も同様な感じで
for(int i=0;i<m_def.GetCount();i++){
  // いろいろ判定
  m_0.Add(i);
}
でいいですよね?
どこにどういった問題が?

大三元 2006/06/22(木) 14:47:21
>m_def[m_1[i]].m_hoge
こういう参照の仕方ができるんですね?
しりませんでした。
C言語のポインタと同様な感じですね(^_^)

>ちなみに私はインデックス保持派っすね
俺もそうです。
そのつもりで作ってます。
1つ前の発言のように
CArray<WORD,WORD>m_0;を登録しておく方法がよいってことですか?

たいちう 2006/06/22(木) 14:53:50
実データがm_defで、m_1〜m_5は、その部分集合ですよね?

CArray<KATA> m_def;
CArray<KATA*> m_1, m_2, m_3, m_4, m_5;

私ならまず、↑のようにすると思います。
速度もメモリ消費量も気にするほどのことではなさそう、
という予想で、プログラムの作りやすさを優先します。


> CArray<WORD,WORD>m_0;を登録しておく方法がよいってことですか?

m_0には、WORD型で、0, 1, 2, 3, ... , というデータが入るのならば、
何の意味もないと思いますが。

PATIO 2006/06/22(木) 14:59:45
> 今思いついたのですが、
> CArray<KATA,KATA>m_def;
> CArray<WORD,WORD>m_1;
> の型が異なるために余計な判定や
> 設計に苦労してます。

この設計でなぜ大変になるのか良くわからないです。
m_1に入るのはインデックスですからそんなに面倒とも思えません。
CArrayのインデックスの型にあわせたいのであれば、
CArray<int, int> m_1;とすれば済む事ですし。
使い方にしてもねこたまさんの書き込みを見れば、
対して面倒でもない事が直ぐわかります。

通常、データの二重管理はデータの整合性が狂う可能性を考えると
真っ先に避けて考える方法だと思います。
ましてや今回の話の内容からすると最大で同じデータを5重に持つことすらありえそうです。
もっとも、参照だけであれば重複して持ったとしても致命的なバグにはならなそうですが。

あと、使わなくてもパフォーマンスも出るし、そこまで複雑な作りになるわけでもないの
であれば、
メモリは極力最小限に留めるべきではと私は思います。
Windowsは自分が作ったアプリ以外のアプリも同時動いている可能性があるわけですし、
出来る限り無駄は省くべきでしょう。
メモリ使用量を減らそうとするあまり不必要に複雑化するのはよくないと思いますが、
今回の件はそこまで複雑になっているとは思えません。

PATIO 2006/06/22(木) 15:05:26
> CArray<WORD,WORD>m_0;を登録しておく方法がよいってことですか?

これは必要ないと思います。
というか、これを何に使うのでしょう?
ねこたまさんの書き方が出来る時点で必要ないと思いますけれど。
なぜ、必要なのかが理解できないです。

大三元 2006/06/22(木) 15:08:39
>実データがm_defで、m_1〜m_5は、その部分集合ですよね?
そうです。

>私ならまず、↑のようにすると思います。
以前はそのように考えていました。
http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200606/06060056.txt

>通常、データの二重管理はデータの整合性が狂う可能性を考えると
>真っ先に避けて考える方法だと思います。
そのように考えています。
PATIOさんの言ってることは全て正しいと思うし、
自分もいつもその考えで設計しています。

PATIO 2006/06/22(木) 15:16:07
インデックスで管理しないのであれば、たいちうさんが書いているような
ポインタで参照できるようにする方法もありでしょうね。

あと、15バイトで16000件最大なら240KB程度の話なので
クラスメンバー上は単純に

KATA*      m_pDef;

とでもしておいて
クラスのコンストラクタでm_pDef = new KATA[16000];として確保しておいて

CArray<KATA*> m_1, m_2, m_3, m_4, m_5;
としてポインタの配列にしておけば、直接参照可能ですね。

ちなみにですが、CArrayの各要素のポインタって取れましたっけ?
CArrayのソースを見ればわかるかもしれませんけれど。

たいちう 2006/06/22(木) 15:30:13
> ちなみにですが、CArrayの各要素のポインタって取れましたっけ?
> CArrayのソースを見ればわかるかもしれませんけれど。

CArray::GetDataで、先頭が取れますが、
これを積極的に使うならばCArrayを使う意味がないですね。

大三元 2006/06/22(木) 15:32:17
なるほど、そういう方法もありますね。
CArray<KATA*>のほうが楽かもしれませんね?
でも2バイトずつ増えますね。

>ちなみにですが、CArrayの各要素のポインタって取れましたっけ?
各要素のポインタとは?どういう意味?

PATIO 2006/06/22(木) 15:40:06
CArray内の要素の管理はCArrayがやっていますから
内部にあるデータにいつも直接アクセスしているとは限らないと言う意味です。
例えば、GetAtした場合、返却される参照先のインスタンスは一時オブジェクトで
ある可能性があるということです。基本的にクラスが内部に持っているデータを
直接扱うことを避ける設計をします。この方がデータの安全性が高いからです。
CArray::GetDataで先頭ポインタが取れますが、CArrayにAddしたタイミングで
内部的なメモリの再確保が発生して先頭のポインタが変わる事だって考えられます。
クラスを使う場合、その辺の事まで考えておかないといけません。

PATIO 2006/06/22(木) 15:51:10
CArrayを使う設計で動的にメモリを確保して使うのであれば、
インデックスを保持する方法の方が自然な実装だと思います。
CArrayそのものもインデックスでアクセスする事を基本にしたクラスですから。
ポインタの配列でデータを扱うのであれば、m_defはKATAのポインタで宣言して
newで配列確保した方が自然でしょう。
後考えられるとしたら、ポインタの配列でm_defを作成しておいて
m_1・・・側もポインタの配列にするとかかな。
この場合は、m_def要素を追加するたびにnew KATAが必要になりますけどね。
やり方は色々あるので試行錯誤してベストを探るのもまた勉強ですね。

PATIO 2006/06/22(木) 15:52:28
失礼、脱字。

誤)
> この場合は、m_def要素を追加するたびにnew KATAが必要になりますけどね。

正)
この場合は、m_defに要素を追加するたびにnew KATAが必要になりますけどね。

大三元 2006/06/22(木) 16:04:29
>これは必要ないと思います。
>というか、これを何に使うのでしょう?
>ねこたまさんの書き方が出来る時点で必要ないと思いますけれど。
>なぜ、必要なのかが理解できないです。
これに関してそもそもの質問の根源なのですが、
検索条件を判定し、m_1〜m_5にセットするのですが、
判定する元のデータがm_defを直接見るか、
m_1〜m_4でインデックスを取得するかで処理が変わります。
それをうまく統一できないかな〜と思いまして。。

m_KenskuNumの値により検索元のデータを決めます。
一度も検索してない時は0(m_defを参照し、m_1にセット)。
0のときと、1〜4のときでif文で分ける必要があります。

大三元 2006/06/22(木) 16:06:26
[[解決]]
>CArrayを使う設計で動的にメモリを確保して使うのであれば、
>インデックスを保持する方法の方が自然な実装だと思います。
僕もそう思います。

この方法で設計してみます。
この方法がやはりベストだと思うので!

REE 2006/06/22(木) 16:32:55
m_0はいいアイデアだと思いますよ

さらにm_0〜m_5を纏めて
CArray<WORD,WORD> m[6]; というのもありかも・・

大三元 2006/06/22(木) 16:37:21
>m_0はいいアイデアだと思いますよ
そう思いますか?よかった。
>CArray<WORD,WORD> m[6]; というのもありかも・・
これが一番シンプルですねぇ(^o^)

PATIO 2006/06/22(木) 16:39:40
> これに関してそもそもの質問の根源なのですが、
> 検索条件を判定し、m_1〜m_5にセットするのですが、
> 判定する元のデータがm_defを直接見るか、
> m_1〜m_4でインデックスを取得するかで処理が変わります。
> それをうまく統一できないかな〜と思いまして。。

この部分を無理に一つの処理で行おうとするからかえって面倒になるのでは?
検索を行った場合と行わない場合でばっさり処理を分けてしまうのも手でしょうし、
例えば、こんな方法もありだと思います。
(コンパイルは通していないので参考程度に)

メンバー変数に
CArray<WORD,WORD> m_index[5];
としておいて

int countMax;
if(m_KenskuNum == 0)
{
    countMax = m_def.GetSize();
}
else
{
    countMax = m_index[m_KenskuNum - 1].GetSize();
}

int    iIndex;
for(int i = 0; i < countMax; i++)
{
    if(m_KenskuNum == 0)
    {
        iIndex = i;
    }
    else
    {
        iIndex = (m_index[m_KenskuNum - 1])[i];
    }

    // この辺で参照する。
    m_def[iIndex]とすれば、参照可能。
}

この辺は設計と言うよりもコーディングのレベルの話ですね。

PATIO 2006/06/22(木) 16:43:52
確かにm_0に相当する物があれば、if文はいらなくなりますね。
ただ、この場合は逆にm_KenskuNum==0の場合だけが違う処理なんだということが
わかった方が後から見たと気に直感的にわかっていいような気もします。

大三元 2006/06/22(木) 16:51:16
>例えば、こんな方法もありだと思います。
その方法はまずまっさきに思いつきました。
しかし、for文の中でif文で毎回判定するのはよくないかな!?と、思いました。
最大で16000回も判定するもんで・・・

そして、
>int    iIndex;
のあとにまずif文で分けてしまい、
それ以下の処理を両方に記述する方法にしようとしました。
しかし、違うのは、iIndexに代入するまでの2行ほどで
以下は同様です。
なので同じ処理を何行も記述するので
無駄かな?美しくないな?と思いまして、
なんかいい方法はないかと質問させていただきました。

その中でm_0の方法を思いつきました。
それならif文が必要なくなります。
メモリは2*16000無駄になりますが・・・

大三元 2006/06/22(木) 16:56:19
>確かにm_0に相当する物があれば、if文はいらなくなりますね。
>ただ、この場合は逆にm_KenskuNum==0の場合だけが違う処理なんだということが
>わかった方が後から見たと気に直感的にわかっていいような気もします。
う〜ん、それは人によりますね。
判定がいっぱいあったほうが追いづらい人もいるし、
俺は・・・どっちだろう?
まぁ、この場合この0だけ違うというのを忘れることはないと思いますけど。
そう思うならm_0の方法がよいのかな?

PATIO 2006/06/22(木) 17:06:22
あうあう。また誤字が。

誤)
わかった方が後から見たと気に直感的にわかっていいような気もします。

正)
わかった方が後から見た時に直感的にわかっていいような気もします。

PATIO 2006/06/22(木) 17:10:33
まあ、この辺は個人の好みの範疇でよいのではと思います。
今時のPCであれば、この程度のif文なら足を引っ張るほどにはなら無そうですし。

大三元 2006/06/22(木) 17:13:15
[[解決]]
わかりました〜。
自分の好きなやり方でやってみます。
それでなんかまずかったらほかの方法でやってみます。
ありがとうございます。

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