10000回以上反復realloc
するループのすべての反復で使用しています。for
これは良い習慣ですか?何realloc
度も呼び出された場合、エラーが発生しますか?
10000回以上反復realloc
するループのすべての反復で使用しています。for
これは良い習慣ですか?何realloc
度も呼び出された場合、エラーが発生しますか?
メモリが不足しない限り失敗することはありませんが(他のアロケータでも発生します)、必要なストレージを事前に見積もることができれば、コードは通常はるかに高速に実行されます。
多くの場合、ストレージ要件を決定するためだけに追加のループを実行する方がよいでしょう。
それがダメだとは言いませんrealloc
が、それも良い習慣ではありません。
最近この質問に出くわしました。かなり古いものですが、情報が完全に正確ではないと感じています.
必要なメモリのバイト数を事前に決定するための余分なループについては、
余分なループを使用することは、常に、または多くの場合、より良いとは限りません。必要なメモリーの量を事前に決定するには何が関係していますか? これにより、高価で不要な追加の I/O が発生する可能性があります。
一般的な realloc の使用に関しては、
関数の alloc ファミリ (malloc、calloc、realloc、および free) は非常に効率的です。基盤となる alloc システムは、OS から大きなチャンクを割り当て、要求に応じてパーツをユーザーに渡します。realloc を連続して呼び出すと、ほとんどの場合、現在のメモリ位置に追加のスペースが追加されます。
システムが最初からより効率的かつ正確にヒープ プールを維持するのであれば、自分でヒープ プールを維持する必要はありません。
これを行うと、メモリが断片化する危険があります。これによりパフォーマンスが低下し、32 ビット システムの場合、メモリの大規模な連続ブロックが利用できないため、メモリ不足が発生する可能性があります。
配列の長さを毎回1ずつ増やしていると思います。その場合、容量と長さを追跡し、現在の容量を超える長さが必要な場合にのみ容量を増やす方がはるかに優れています。容量を増やすときは、1 よりも多くしてください。
もちろん、標準のコンテナがこのようなことをしてくれるので、使えるならそうするのがベストです。
前に述べたことに加えて、考慮すべきことがいくつかあります。
のパフォーマンスは、次のrealloc(<X-sized-buf>, X + inc)
2 つの要素に依存します。
malloc(N + inc)
低下しますO(N)
memcpy(newbuf, oldbuf, N)
ますO(N)
つまり、インクリメントが小さいが既存のブロックが大きいrealloc()
場合、パフォーマンスはO(N^2)
既存のデータ ブロックのサイズに関係します。バブルソートとクイックソートを考えてみてください...
小さなブロックから始めれば比較的安価ですが、再割り当てされるブロックが大きい場合はかなり不利になります。軽減するには、既存のサイズに比べて小さくないinc
ことを確認する必要があります。一定量の再割り当ては、パフォーマンスの問題のレシピです。
さらに、大きな増分で成長した場合でも (たとえば、新しいサイズを古いサイズの 150% にスケーリングした場合) 、大きなバッファーを再割り当てすることでメモリ使用量が急増します。既存のコンテンツのコピー中に、2 倍の量のメモリを使用します。次のシーケンス:
addr = malloc(N);
addr = realloc(addr, N + inc);
したがって、次よりも (はるかに) 早く失敗します。
addr[0] = malloc(N);
addr[1] = malloc(inc);
realloc()
成長する必要のないデータ構造があります。リンク リスト、スキップ リスト、インターバル ツリーはすべて、既存のデータをコピーすることなくデータを追加できます。C++vector<>
はこのように成長します。初期サイズの配列から始まり、それを超えて拡大すると追加し続けますが、そうではありませんrealloc()
(つまり、コピーします)。そのようなものを実装する(または既存の実装を使用する)ことを検討してください。
2 のべき乗のサイズに再割り当てする必要があります。これは stl で使用されるポリシーであり、メモリの管理方法に適しています。realloc don't は、メモリが不足している場合 (および NULL を返す場合) を除いて失敗しませんが、既存の (古い) データを新しい場所にコピーするため、パフォーマンスの問題になる可能性があります。
ループ内で同じバッファを realloc() している場合、追加のメモリ要求を恐れるのに十分なメモリがある限り、問題はありません:)
通常、 realloc() は、作業している既存の割り当てられたスペースを拡張/縮小し、同じポインターを返します。その場でそうしないと、コピーと解放が関係するため、この場合、realloc() はコストがかかります。また、新しいポインターも取得します:)