動的配列でのメモリー不足

解決


Syake  2005-03-03 05:31:35  No: 13500

皆さんこんばんは。
初歩的な質問かもしれませんが、動的配列の制限なりを
教えたいただければと思います。

var
 arrTemp :array of Integer;

パターン1
for i := 0 to 強大な数 do
begin
  SetLength(arrTemp,i+1);
  arrTemp[i] := i;
end;

パターン2
SetLength(arrTemp,巨大な数);
for i := 0 to  巨大な数 do
begin
  arrTemp[i] := i;
end;

で、実行結果
パターン1では「メモリー不足」のエラーで中断。
パターン2では正常に実行される。

といっても、上記内容では1000や10000ではどちらもエラーにはならない
と思います。
実際にはRecord型の動的配列で処理した結果、パターン1で1000程度の
数ではエラーにならず大丈夫と思っていましたが、故あって5000程度の
処理を行ったところ「メモリー不足」で処理が中断してしまいました。
結果的には、パターン2に変更したらエラーはなくなりました。

どうも、「結果的には同じ処理じゃん。」と思って記述していましたが、
落とし穴がありそうです。

この辺の情報(理由・原因・注意事項)などありましたらご教授いただけれ
ばと思います。
また、今回のケースはあらかじめ要素数が確定してたことも幸いしました。
現状では遭遇していませんが、万一事前に要素数が確定しない場合などは
どの様に処理したらよいのかわかりません。
よろしくお願いします。


にしの  2005-03-03 06:52:37  No: 13501

こちらが参考になるかと思います。
http://www2.big.or.jp/~osamu/Delphi/delphi-browse.cgi?index=060849


りおりお  2005-03-03 09:03:37  No: 13502

> どうも、「結果的には同じ処理じゃん。」と思って記述していましたが、

いやいや、パターン1はとってもダメコードで、わたしには書く勇気がでないほどです。

For は予め回数が分かってるのですからパターン2にすべきです。パターン1は
繰り返しメモリの確保とコピーが行われるのでとっても遅いほかに、ループの
後の方では、コピーする瞬間はほぼ2倍のメモリが必要です。

> 事前に要素数が確定しない場合などは

今の長さは length() で求まる訳ですから、書き込むときに不足するかどうか調べて
例えば100個単位で増減するようにします。パターン1のように1個ずつではあまりに
効率が悪いです。


りおりお  2005-03-03 11:02:20  No: 13503

> コピーする瞬間はほぼ2倍のメモリが必要です。

動的配列は、string 型と同様、参照数を持ったスマートポインタとして実装され
ていますね。ですから、パターン1では、再確保するたびにコピーが行われるた
め遅くなるのはもちろんですが、そこいら中にメモリの断片化が発生します。
ですからメモリマネージャは大忙しで、新たに確保すべき領域を探し回り、見つ
からなければ「メモリ不足」になるのでしょう。

動的配列やstring型に限らず、動的にメモリのサイズを変更するのは、とくに
拡大するときは高いコストが必要です。TMemoryStream などの場合もそうです。
予めサイズが分かっている場合は、一挙にサイズを確保してから操作する方が
一般には実行速度に関しても、メモリの負担に関してもかなり有利です。
また、サイズが予め分からない場合は、じわじわと細切れで増やすより、大きな
固まりとして増やし、メモリの再確保と自動的に行われる既存データのコピーの
回数を出来るだけ減らすべきです。


Syake  2005-03-03 17:15:50  No: 13504

おはようございます。
にしのさん。りおりおさん。
ご指導していただいた内容、大変参考になりました。m(__)m

勉強不足でした。
「素人の付け焼刃は怪我のもと」でした。
もっと、勉強します。今後ともよろしくお願いします。
ありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加