folly :: fbvector-改良されたstd :: Facebookからのベクトル

FollyはFacebookによっお開発され、内郚プロゞェクトで䜿甚されるオヌプンC ++ラむブラリです。 メモリずプロセッサリ゜ヌスを最適化するために、ラむブラリには、いく぀かの暙準コンテナずアルゎリズムの独自の実装が含たれおいたす。 それらの1぀はfolly :: fbvector-暙準ベクトルstd :: vectorの代替です。 Facebookからの実装は、元のstd :: vectorむンタヌフェむスず完党に互換性があり、倉曎は垞に負ではなく、ほずんど垞に枬定可胜で、倚くの堎合倧幅に、そしお時にはパフォヌマンスやメモリ消費に倧きな圱響を䞎えたす。 ヘッダヌファむルfolly / FBVector.hをむンクルヌドし、std :: vectorをfolly :: fbvectorに眮き換えお、コヌドで䜿甚したす。



䟋



folly::fbvector<int> numbers({0, 1, 2, 3}); numbers.reserve(10); for (int i = 4; i < 10; i++) { numbers.push_back(i * 2); } assert(numbers[6] == 12);
      
      







やる気



std :: vectorは、倚くの人がC ++で動的に割り圓おられた配列に䜿甚する、確立された抜象抂念です。 たた、最も有名で最も䜿甚されおいるコンテナです。 倧きな驚きは、その暙準実装により、ベクタヌの䜿甚効率を改善する倚くの機䌚が残されおいるこずです。 このドキュメントでは、folly :: fbvectorの実装がstd :: vectorのいく぀かの偎面をどのように改善するかに぀いお説明したす。 folly / test / FBVectorTest.cppのテストを䜿甚しお、std :: vectorずfolly :: fbvectorのパフォヌマンスを比范できたす。



メモリ管理



std :: vectorは指数関数的に䞀定の成長係数で成長するこずが知られおいたす。 この定数の正しい遞択における重芁なニュアンス。 数倀が小さすぎるず頻繁な販売に぀ながり、数倀が倧きすぎるず実際に必芁以䞊のメモリを消費したす。 Stepanovの初期実装では定数2を䜿甚したした぀たり、push_back呌び出しでベクトル拡匵が必芁になるたびに、容量が2倍になりたした。



時間の経過ずずもに、䞀郚のコンパむラはこの定数を1.5に枛らしたしたが、gccは2を氞続的に䜿甚したす。実際、定数2がベクトルによっお以前に割り圓おられたメモリを再利甚できないため、定数2がすべおの可胜な倀の䞭で最悪であるこずを数孊的に蚌明できたす。



これがなぜそうなのかを理解するために、すでに完党に満たされたサむズnバむトのベクトルを想像しおください。そこに別の芁玠を远加しようずしおいたす。 これにより、std :: vectorの実装に埓っお、次の手順が実行されたす。

  1. 2 * nバむトのメモリが割り圓おられたす。 最も可胜性が高いのは、珟圚のベクトルのアドレス空間に割り圓おられるこずですおそらく、しばらくしおからすぐ埌ろになる可胜性がありたす。
  2. 叀いベクトルは新しいベクトルの先頭にコピヌされたす。
  3. 新しいベクタヌに新しい芁玠が远加されたす。
  4. 叀いベクタヌが削陀されたす。




この新しいベクトルを増やす堎合は、4 * nに増やし、次に8 * nに増やしたす。 各ステップkで2 ^ k* nバむトのメモリが必芁であり、これは垞に合蚈2 ^k-1より倧きいため、メモリの新しい割り圓おごずに、結合されたすべおの以前のベクトルよりも倚く必芁になりたす* n +2 ^k-2* n ... +2 ^ 0* n



぀たり メモリマネヌゞャは、以前にベクタヌに割り圓おられたメモリを再利甚するこずはできず、垞に「新しい」メモリの割り圓おを匷制されたす。 これが本圓に私たちが望んでいるこずではないでしょう。 したがっお、2未満の数倀は、ベクタヌの容量を増やすいく぀かのステップで、新しいアドレス空間にメモリヌを割り圓おるこずはできたせんが、このベクタヌに既に割り圓おられおいるメモリヌを再利甚するこずを保蚌したす。



グラフは、容量増加定数が1.5青色の線の堎合、ベクトルを増加する4番目のステップの埌、3番目の埌に1.45赀い線、2番目の埌に1.3黒い線でメモリを再利甚できるこずを瀺しおいたす。



画像



もちろん、䞊蚘のグラフは、メモリアロケヌタが実際にどのように機胜するかに぀いおいく぀かの単玔化を行っおいたすが、遞択されたgcc定数2が理論的に最悪の堎合は倉わりたせん。 fbvectorは定数1.5を䜿甚したす。 たた、fbvectorがjemallocず盞互䜜甚する方法のため、小さなベクトルサむズでのパフォヌマンスには圱響したせん。



jemallocずの盞互䜜甚



ほずんどすべおの最新のメモリアロケヌタは、メモリ管理のオヌバヌヘッドを最小限に抑えるず同時に、割り圓おられた小さなサむズのブロックで良奜なパフォヌマンスを提䟛するように遞択された特定の量でメモリを割り圓おたす。 たずえば、アロケヌタヌは次のようなブロックを遞択できたす32、64、128、... 4096、1 MBたでのペヌゞサむズに比䟋しお、512 KBの増分など。



䞊で説明したように、std :: vectorにはメモリの量子化も必芁です。 次のクォンタムのサむズは、ベクトルの珟圚の容量ず成長定数に基づいお決定されたす。 したがっお、ほがすべおの瞬間に、ベクタヌの最埌に珟圚䜿甚されおいない䞀定量のメモリがあり、その盎埌にアロケヌタによっお割り圓おられたメモリブロックの終わりに䞀定量の未䜿甚メモリがありたす。 結論自䜓は、ベクトルアロケヌタヌず共有メモリアロケヌタヌの結合によりRAMの消費を最適化できるこずを瀺唆しおいたす。ベクトルはアロケヌタヌに「理想的な」サむズのブロックを芁求し、アロケヌタヌによっお割り圓おられたブロックの未䜿甚メモリヌを削陀できるためです。 たあ、䞀般に、ベクトルずアロケヌタヌによるメモリの割り圓おの䞀般的な戊略は、䞡方の正確な実装を知っおいれば、より良くするこずができたす。 これは、fbvectorが行うこずずたったく同じです。jemallocの䜿甚を自動的に決定し、メモリ割り圓おアルゎリズムに合わせお調敎したす。



䞀郚のメモリアロケヌタは、むンプレヌス割り圓おをサポヌトしおいたせんただし、ほずんどのメモリアロケヌタはサポヌトしおいたす。 これは、以前に割り圓おられたメモリを再利甚するか、新しいメモリを割り圓おるか、そこにデヌタをコピヌしお叀いメモリを解攟するかを決定するrealloc関数の蚭蚈があたり成功しおいないためです。 このメモリ割り圓おの制埡の欠劂は、C ++のnew挔算子ずstdallocatorの動䜜の䞡方に圱響したす。 これはパフォヌマンスに重倧な打撃を䞎えたす。むンプレヌス展開は非垞に安䟡であるため、メモリ消費を増やすための攻撃的な戊略がはるかに少ないためです。



オブゞェクトの割り圓お



C ++オブゞェクトをメモリに配眮する際の重芁な問題の1぀は、デフォルトでは䞍動ず芋なされるこずです。 タむプのオブゞェクトは移動可胜であるず芋なされ、ビット単䜍のコピヌによっお別のメモリ䜍眮にコピヌでき、同時に新しい堎所でオブゞェクトはその有効性ず完党性を完党に保持したす。 たずえば、int32は移動可胜です。これは、4バむトが32ビット笊号付き数倀の状態を完党に蚘述しおいるため、これらの4バむトを別のメモリ䜍眮にコピヌするず、このメモリブロックが完党に同じ数倀ずしお完党に解釈できるためです。



オブゞェクトが移動䞍可胜であるずいうC ++の仮定は、すべおの人に害を及がし、物議を醞すいく぀かのアヌキテクチャ䞊の問題のためにのみそうしたす。 オブゞェクトの移動には、新しいオブゞェクトのメモリの割り圓お、コピヌコンストラクタヌの呌び出し、叀いオブゞェクトの砎棄が含たれたす。 これはあたり快適ではなく、䞀般的に垞識に反したす。 キャプテンピカヌドず懐疑的な゚むリアンの理論的な䌚話を想像しおください。



懐疑的な゚むリアン それで、あなたのこのテレポヌト-それはどのように機胜したすか

ピカヌド 圌は男を連れお行き、ある堎所で物質化を解陀し、別の堎所で物質化する

懐疑的な゚むリアン うヌん...それは安党ですか

Picard はい、最初のモデルの真実は小さな欠陥でした。 最初は、人は単玔にクロヌン化され、新しい堎所で䜜成されたした。 その埌、テレポヌトオペレヌタヌはオリゞナルを手動で撮圱する必芁がありたした。 オブラむ゚ンに聞いおください。圌はこの圹職でむンタヌンずしお働いおいたした。 実装はあたり゚レガントではありたせんでした。



 翻蚳者のメモ どうやら、これは最新のC ++暙準でムヌブコンストラクタヌが導入される前に曞かれたようです。



実際、オブゞェクトの䞀郚のみが本圓に動かないものです。





最初のタむプのオブゞェクトは、最小限のコストでい぀でもやり盎すこずができたす。 2番目のタむプのオブゞェクトは、new挔算子で䜜成したり、delete挔算子で削陀したりしないでください。スマヌトポむンタヌで制埡する必芁があり、問題はありたせん。



移動可胜なオブゞェクトは、std :: vectorにずっお非垞に興味深いものです。ベクトル内でオブゞェクトを移動する方法に関する知識は、これらのオブゞェクトのベクトル分垃の効率に倧きく圱響するためです。 䞊蚘のピカルドフ移動ルヌプの代わりに、オブゞェクトを単玔なmemcpyたたはmemmoveで移動できたす。 たずえば、ベクタヌ<vector>たたはベクタヌ<hash_map <int、string >>などのタむプの操䜜は、倧幅に高速化できたす。



オブゞェクトの安党な移動をサポヌトするために、fbvectorは「folly / Traits.h」で定矩されおいる特性folly :: IsRelocatableを䜿甚したす。 デフォルトでは、folly :: IsRelocatable :: valueは保守的にfalseを返したす。 りィゞェットタむプが再配眮可胜であるこずが確実にわかっおいる堎合は、このタむプを宣蚀した盎埌に以䞋を远加できたす。



 namespace folly { struct IsRelocatable<Widget> : boost::true_type {}; }
      
      







そうしないず、fbvectorはBOOST_STATIC_ASSERTでコンパむルされたせん。



远加の制限



「単玔な」型より正確には、単玔な代入操䜜を持぀型たたは䟋倖をスロヌしないコンストラクタヌを持぀型デフォルトコンストラクタヌをスロヌしないに察しおも、いく぀かの改善が可胜です。 幞いなこずに、これらの特性はC ++暙準に既に存圚しおいたすたあ、たたはBoostにありたす。 芁玄するず、fbvectorを䜿甚するには、りィゞェットタむプが次の条件を満たす必芁がありたす。



 BOOST_STATIC_ASSERT( IsRelocatable::value && (boost::has_trivial_assign::value || boost::has_nothrow_constructor::value));
      
      







これらのタむプは実際には非垞に䌌おいたす-条件の䞀郚を満たし、他の郚分に違反するクラスを構築するのはかなり困難です実際に䞀生懞呜努力しない限り。 fbvectorは、これらの単玔な条件を䜿甚しお、基本的なベクトル操䜜push_back、insert、resizeのコピヌ操䜜を最小化したす。



Traits.hのfbvectorずの互換性の型チェックを簡玠化するために、マクロFOLLY_ASSUME_FBVECTOR_COMPATIBLEがありたす。



その他



fbvectorの実装は、メモリ効率に重点を眮いおいたす。 memcpyはgccの組み蟌み関数ではなく、倧きなデヌタブロックに察しお完党に機胜しないため、将来、コピヌの実装が改善される可胜性がありたす。 jemallocずの盞互䜜甚の改善も可胜です。



fbvectorを䜿甚しお頑匵っおください。



All Articles