web-dev-qa-db-ja.com

malloc()呼び出しの量を最小限に抑えると、パフォーマンスが向上しますか?

2つのアプリケーションについて考えてみます。1つ(num。1)はmalloc()を何度も呼び出すもので、もう1つ(num。2)はmalloc()を数回呼び出すものです。どちらのアプリケーションも同じメモリ量を割り当てます(100MBと想定)。
次のmalloc()呼び出しが高速になるアプリケーションは、#1と#2のどちらですか。
言い換えると、malloc()には、メモリ内に割り当てられた場所のインデックスがありますか?

28
Dor

もちろん、これは完全にmallocの実装に依存しますが、この場合、freeの呼び出しがないため、ほとんどのmallocの実装はおそらく同じアルゴリズム速度を提供します。

別の回答がコメントしたように、通常は空きブロックのリストがありますが、無料と呼んでいない場合は1つだけなので、どちらの場合もO(1))になります。

これは、どちらの場合も、ヒープに割り当てられたメモリが十分に大きいことを前提としています。ケース#1の場合、各割り当てにはメタデータを格納するためのメモリオーバーヘッドが含まれるため、より多くの合計メモリが割り当てられます。その結果、sbrk()を呼び出すか、ケース#1のヒープを拡張するために同等のものを呼び出す必要があります。追加のオーバーヘッドを追加します。

新しい割り当てのメモリ配置は同じではないため、キャッシュやその他の2次効果のためにおそらく異なるでしょう。

一部のメモリブロックを解放している場合は、断片化が少ないため、#2の方が高速である可能性が高く、検索する空きブロックのリストが少なくなります。

すべてのメモリブロックを解放した場合、それはまったく同じになるはずです。これは、正常な解放の実装では、ブロックが合体して単一のメモリ領域に戻るためです。

10
benno

あなたは2つの質問をしました:

  • 次のmalloc()呼び出しが高速になるアプリケーション、#1または#2?
  • 言い換えると、malloc()にはメモリ内に割り当てられた場所のインデックスがありますか?

あなたはそれらが同じ質問であることを暗示しましたが、そうではありません。後者の質問に対する答えは「はい」です。

どちらが速くなるかについては、言うことは不可能です。これは、アロケータアルゴリズム、マシンの状態、現在のプロセスの断片化などによって異なります。

ただし、あなたの考えは正しいです。mallocの使用がパフォーマンスにどのように影響するかを考える必要があります。かつて私が書いた、たくさんの小さなメモリの塊を使用し、それぞれがmalloc()で割り当てられたアプリがありました。正しく動作しましたが、低速でした。 mallocへの多くの呼び出しを1つだけに置き換えてから、アプリ内でその大きなブロックをスライスしました。それははるかに速かった。

このアプローチはお勧めしません。これは、mallocの使用がパフォーマンスに重大な影響を与える可能性があるという点を示しているにすぎません。

私のアドバイスはそれを測定するです。

19
Cheeso

Mallocは、割り当てるブロックを見つけるために、空きブロックのリンクリストを実行する必要があります。これには時間がかかります。したがって、#1は通常遅くなります:

  • Mallocを頻繁に呼び出すほど、時間がかかります。したがって、呼び出しの数を減らすと、速度が向上します(ただし、それが重要かどうかは、正確な状況によって異なります)。

  • さらに、多くの小さなブロックをmallocする場合、それらのブロックを解放すると、いくつかの大きなブロックのみを割り当てて解放する場合よりもはるかに多くのヒープがフラグメント化されます。そのため、ヒープ上にいくつかの大きなブロックではなく、多くの小さな空きブロックが存在する可能性があります。したがって、mallocは、割り当てに適したブロックを見つけるために、空き領域リストをさらに検索する必要があります。どちらが再びそれらを遅くします。

6
Jason Williams

これらはもちろん実装の詳細ですが、通常はfree()がメモリを空きブロックのリストに挿入します。次に、malloc()はこのリストを調べて、適切なサイズ以上の空きブロックを探します。通常、これが失敗した場合にのみ、malloc()はカーネルに追加のメモリを要求します。

複数の隣接するブロックを単一のより大きなブロックにいつ合体させるかなど、他の考慮事項もあります。

また、malloc()が高価であるもう1つの理由:malloc()が複数のスレッドから呼び出される場合、これらのグローバル構造で何らかの同期が必要です。 (つまり、ロック。)複数のスレッドに適した最適化スキームを備えたmalloc()実装が存在しますが、複数のスレッドがそれらのロックを争うため、一般に、マルチスレッドセーフを維持するとコストが増加します。お互いの進行をブロックします。

3
asveikau

常に malloc()を使用してより良い仕事をして、メモリの大きなチャンクを割り当て、それを自分で細分化することができます。 Malloc()は、一般的なケースで適切に機能するように最適化されており、スレッドを使用するかどうか、またはプログラムの割り当てのサイズを想定していません。

独自のサブアロケータを実装するのが良い考えかどうかは、二次的な質問です。まれに、明示的なメモリ管理はすでに十分に困難です。プログラムをデバッグするための適切な方法がなくても、プログラムを台無しにしてクラッシュさせる可能性のある別のコード層が必要になることはめったにありません。デバッグアロケータを作成している場合を除きます。

2
Hans Passant

答えはそれによって異なります。潜在的な速度低下のほとんどは、malloc()とfree()の組み合わせによるものであり、通常、#1と#2の速度は同じです。

すべてのmalloc()実装にはインデックス付けメカニズムがありますが、インデックスに新しいブロックを追加する速度は、通常、インデックスに既に存在するブロックの数に依存しません。

Mallocの速度低下のほとんどは、2つの原因によるものです。

  • 以前に解放された(ブロック)の中から適切な空きブロックを検索する
  • ロックに関するマルチプロセッサの問題

私自身のほぼ標準に準拠したmalloc()置換ツールmalloc()&& free()を35%から3-4%まで作成し、これら2つの要素を真剣に最適化しました。他の高性能mallocを使用するのも同様の速度だったと思われますが、独自のmallocを使用すると、難解なデバイスへの移植性が高まり、もちろん、場所によっては自由にインライン化できます。

2
Erik Elmgren

1ブロックのメモリを割り当てる方が、多くのブロックを割り当てるよりも高速です。システムコールと利用可能なブロックの検索にはオーバーヘッドがあります。プログラミングでは、操作の数を減らすと、通常、実行時間が短縮されます。

メモリアロケータは、正しいサイズのメモリブロックを見つけるために検索する必要がある場合があります。これにより、実行時間のオーバーヘッドが増加します。

ただし、1つの大きなブロックよりも小さなメモリブロックを割り当てる方が成功する可能性が高くなります。プログラムは1つの小さなブロックを割り当てて解放しますか、それとも小さなブロックを割り当てる(そして保存する)必要がありますか。メモリが断片化すると、使用可能な大きなチャンクが少なくなるため、メモリアロケータはすべてのブロックを合体させて、割り当てに十分な大きさのブロックを形成する必要があります。

プログラムがメモリの多くの小さなブロックを割り当てて破棄している場合は、静的配列を割り当てて、それをメモリに使用することを検討してください。

1
Thomas Matthews

「多く」と「少数」の相対的な違いを定義していませんが、ほとんどのmallocは両方のシナリオでほぼ同じように機能すると思います。この質問は、mallocへの各呼び出しには、システムコールやページテーブルの更新と同じくらいのオーバーヘッドがあることを意味します。 malloc呼び出しを行うとき、たとえばmalloc(14)、脳が死んでいない環境では、mallocは実際には、要求したよりも多くのメモリを割り当てます。多くの場合、システムの倍数MMUページサイズです。14バイトとmallocは新しく割り当てられた領域を追跡するため、OSからさらにメモリを要求する必要があるまで、後の呼び出しですでに割り当てられたメモリのチャンクを返すことができます。

つまり、malloc(14)を100回、またはmalloc(1400)を1回呼び出すと、オーバーヘッドはほぼ同じになります。割り当てられたより大きなメモリチャンクを自分で管理する必要があります。

1