web-dev-qa-db-ja.com

C ++メモリ割り当てメカニズムのパフォーマンス比較(tcmallocとjemalloc)

大量のメモリを割り当てるアプリケーションがあり、mallocよりも優れたメモリ割り当てメカニズムの使用を検討しています。

私の主なオプションは、jemallocとtcmallocです。それらのいずれかを他のものよりも使用することに何か利点はありますか?

http://locklessinc.com/benchmarks.shtml のいくつかのメカニズム(作成者独自のメカニズム--locklessを含む)の間には良い比較があり、それぞれの長所と短所について言及しています。

両方のメカニズムがアクティブであり、絶えず改善されていることを考えると。これら2つの相対的なパフォーマンスについて誰かが洞察や経験を持っていますか?

24
Shayan Pooya

私の記憶が正しければ、主な違いはマルチスレッドプロジェクトでした。

どちらのライブラリも、スレッドに異なるキャッシュからメモリを選択させることでメモリ取得の競合を解消しようとしますが、戦略は異なります。

  • jemalloc(Facebookで使用)はスレッドごとにキャッシュを維持します
  • tcmalloc(Googleから)はキャッシュのプールを維持し、スレッドはキャッシュに対して「自然な」親和性を開発しますが、変更される可能性があります

これは、私が正しく覚えていれば、スレッド管理の面で重要な違いにつながりました。

  • jemallocは、スレッドが静的である場合、たとえばプールを使用する場合に高速になります
  • スレッドが作成/破棄されると、tcmallocが高速になります

jemallocが新しいスレッドIDに対応するために新しいキャッシュをスピンするため、スレッドが突然急増すると、後続の落ち着いたフェーズで(ほとんど)空のキャッシュが残るという問題もあります。

結果として、一般的なケースではtcmallocをお勧めし、非常に特定の用途(アプリケーションの存続期間中のスレッド数の変動が少ない)用にjemallocを予約します。

38
Matthieu M.

私は最近、作業中のプロジェクトでtcmallocを検討しました。これは私が観察したものです:

  • マルチスレッド設定でmallocを頻繁に使用する場合のパフォーマンスが大幅に向上しました。作業中のツールで使用したところ、パフォーマンスはほぼ2倍に向上しました。その理由は、このツールでは、クリティカルループで小さなオブジェクトの割り当てを実行するスレッドがいくつかあったためです。 glibcを使用すると、異なるスレッドでのmalloc/free呼び出し間のロック競合が原因で、パフォーマンスが低下すると思います。

  • 残念ながら、tcmallocはメモリフットプリントを増加させます。上記のツールは、2〜3倍のメモリを消費します(常駐セットの最大サイズで測定)。私たちは実際にメモリフットプリントを削減する方法を探しているので、フットプリントの増加は私たちにとって無駄です。

最終的に、tcmallocを使用せず、代わりにアプリケーションコードを直接最適化することにしました。これは、malloc/freeロックの競合を回避するために、内部ループから割り当てを削除することを意味します。 (不思議なことに、メモリプールを使用するのではなく、圧縮の形式を使用します。)

あなたにとっての教訓は、典型的なワークロードでアプリケーションを注意深く測定する必要があるということです。追加のメモリ使用量に余裕がある場合は、tcmallocが最適です。そうでない場合でも、tcmallocは、スレッド間でのメモリ割り当てへの頻繁な呼び出しを回避することで何が得られるかを確認するのに役立ちます。

12
Alexey

'nedmalloc'ホームページによると、最近のOSのアロケーターは実際にはかなり高速であることに注意してください。

「Windows7、Linux 3.x、FreeBSD 8、Mac OS X 10.6にはすべて最先端のアロケーターが含まれており、実際の結果でサードパーティのアロケーターが大幅に改善する可能性はありません。」

http://www.nedprod.com/programs/portable/nedmalloc

したがって、ユーザーにアップグレードなどを推奨するだけで解決できる可能性があります:)

4
rogerdpack

ここにアロケータについてかなり良い議論があります:

http://www.reddit.com/r/programming/comments/7o8d9/tcmalloca_faster_malloc_than_glibcs​​_open_sourced/

1
SunfiShie

Boehmの保守的なガベージコレクター の使用を検討することもできます。基本的に、ソースコード内のすべてのmallocGC_malloc(etc ...)に置き換え、わざわざfreeを呼び出す必要はありません。 BoehmのGCはmallocよりも速くメモリを割り当てません(ほぼ同じか、30%遅くなる可能性があります)が、役に立たないメモリゾーンを自動的に処理するという利点があり、プログラムが改善される可能性があります(そして確かにコーディングが容易になります。あなたはもう無料を気にしないので)。また、ベームのGCは、C++アロケーターとして 使用 することもできます。

mallocが遅すぎると本当に思っている場合(ただし、ベンチマークを行う必要があります。ほとんどのmalloc-はマイクロ秒未満で完了します)、プログラムの割り当て動作を完全に理解している場合は、置き換えることができます。特別なアロケータを使用したいくつかのmalloc-(たとえば、mmapを使用してカーネルから大きなチャンクでメモリを取得し、自分でメモリを管理できます)。しかし、それを行うのは苦痛だと思います。 C++には、 allocator の概念と std::allocator_traits があり、ほとんどの標準的な containers そのようなアロケータを受け入れるテンプレート( std::allocator も参照)、例: std::vector などへのオプションの2番目のテンプレート引数。

他の人が示唆しているように、mallocがボトルネックであると思われる場合は、データをチャンクで(またはアリーナを使用して)、または単に配列で割り当てることができます。

場合によっては、特殊なコピー ガベージコレクター (一部のデータ用)を実装すると役立つ場合があります。おそらく [〜#〜] mps [〜#〜] を考えてみてください。

ただし、時期尚早の最適化は悪であることを忘れないでください。アプリケーションのベンチマークとプロファイルを作成して、時間が失われる場所を正確に理解してください。

あなたの投稿ではスレッド化については触れられていませんが、CとC++の割り当て方法を組み合わせる前に、メモリプールの概念を調査します。BOOSTには良いものがあります。

1
Martin