皆さんこんばんは。
初歩的な質問かもしれませんが、動的配列の制限なりを
教えたいただければと思います。
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に変更したらエラーはなくなりました。
どうも、「結果的には同じ処理じゃん。」と思って記述していましたが、
落とし穴がありそうです。
この辺の情報(理由・原因・注意事項)などありましたらご教授いただけれ
ばと思います。
また、今回のケースはあらかじめ要素数が確定してたことも幸いしました。
現状では遭遇していませんが、万一事前に要素数が確定しない場合などは
どの様に処理したらよいのかわかりません。
よろしくお願いします。
こちらが参考になるかと思います。
http://www2.big.or.jp/~osamu/Delphi/delphi-browse.cgi?index=060849
> どうも、「結果的には同じ処理じゃん。」と思って記述していましたが、
いやいや、パターン1はとってもダメコードで、わたしには書く勇気がでないほどです。
For は予め回数が分かってるのですからパターン2にすべきです。パターン1は
繰り返しメモリの確保とコピーが行われるのでとっても遅いほかに、ループの
後の方では、コピーする瞬間はほぼ2倍のメモリが必要です。
> 事前に要素数が確定しない場合などは
今の長さは length() で求まる訳ですから、書き込むときに不足するかどうか調べて
例えば100個単位で増減するようにします。パターン1のように1個ずつではあまりに
効率が悪いです。
> コピーする瞬間はほぼ2倍のメモリが必要です。
動的配列は、string 型と同様、参照数を持ったスマートポインタとして実装され
ていますね。ですから、パターン1では、再確保するたびにコピーが行われるた
め遅くなるのはもちろんですが、そこいら中にメモリの断片化が発生します。
ですからメモリマネージャは大忙しで、新たに確保すべき領域を探し回り、見つ
からなければ「メモリ不足」になるのでしょう。
動的配列やstring型に限らず、動的にメモリのサイズを変更するのは、とくに
拡大するときは高いコストが必要です。TMemoryStream などの場合もそうです。
予めサイズが分かっている場合は、一挙にサイズを確保してから操作する方が
一般には実行速度に関しても、メモリの負担に関してもかなり有利です。
また、サイズが予め分からない場合は、じわじわと細切れで増やすより、大きな
固まりとして増やし、メモリの再確保と自動的に行われる既存データのコピーの
回数を出来るだけ減らすべきです。
おはようございます。
にしのさん。りおりおさん。
ご指導していただいた内容、大変参考になりました。m(__)m
勉強不足でした。
「素人の付け焼刃は怪我のもと」でした。
もっと、勉強します。今後ともよろしくお願いします。
ありがとうございました。
ツイート | ![]() |