たとえば、私は既知のsizeof(A)とsizeof(B)を持つstd :: mapを持っていますが、mapにはN個のエントリがあります。そのメモリ使用量をどのように推定しますか?それは次のようなものだと思います
(sizeof(A) + sizeof(B)) * N * factor
しかし、要因は何ですか?多分違う式?
多分上限を求める方が簡単ですか?
推定値は
_(sizeof(A) + sizeof(B) + ELEMENT_OVERHEAD) * N + CONTAINER_OVERHEAD
_
追加する要素ごとにオーバーヘッドがあり、マップを格納するデータ構造に使用されるデータ構造を維持するための固定オーバーヘッドもあります。これは通常、 Red-Black Tree などのバイナリツリーです。たとえば、GCC C++ STL実装では、_ELEMENT_OVERHEAD
_はsizeof(_Rb_tree_node_base)
になり、_CONTAINER_OVERHEAD
_はsizeof(_Rb_tree)
になります。上の図には、マップの要素を格納するために使用されるメモリ管理構造のオーバーヘッドも追加する必要があります。
さまざまな大規模なコレクションのコードのメモリ消費量を測定することで、見積もりにたどり着く方がおそらく簡単です。
Curtis Bartleyによる MemTrack を使用できます。これは、デフォルトのメモリアロケータに代わるものであり、メモリの使用状況を割り当てのタイプまで追跡できます。
出力の例:
-----------------------
Memory Usage Statistics
-----------------------
allocated type blocks bytes
-------------- ------ -----
struct FHRDocPath::IndexedRec 11031 13.7% 2756600 45.8%
class FHRDocPath 10734 13.3% 772848 12.8%
class FHRDocElemPropLst 13132 16.3% 420224 7.0%
struct FHRDocVDict::IndexedRec 3595 4.5% 370336 6.2%
struct FHRDocMDict::IndexedRec 13368 16.6% 208200 3.5%
class FHRDocObject * 36 0.0% 172836 2.9%
struct FHRDocData::IndexedRec 890 1.1% 159880 2.7%
struct FHRDocLineTable::IndexedRec 408 0.5% 152824 2.5%
struct FHRDocMList::IndexedRec 2656 3.3% 119168 2.0%
class FHRDocMList 1964 2.4% 62848 1.0%
class FHRDocVMpObj 2096 2.6% 58688 1.0%
class FHRDocProcessColor 1259 1.6% 50360 0.8%
struct FHRDocTextBlok::IndexedRec 680 0.8% 48756 0.8%
class FHRDocUString 1800 2.2% 43200 0.7%
class FHRDocGroup 684 0.8% 41040 0.7%
class FHRDocObject * (__cdecl*)(void) 36 0.0% 39928 0.7%
class FHRDocXform 516 0.6% 35088 0.6%
class FHRDocTextColumn 403 0.5% 33852 0.6%
class FHRDocTString 407 0.5% 29304 0.5%
struct FHRDocUString::IndexedRec 1800 2.2% 27904 0.5%
ランタイムメモリのフットプリントを本当に知りたい場合は、カスタムアロケータを使用して、マップの作成時に渡します。 Josuttisの本と彼の this ページを参照してください(カスタムアロケーターの場合)。
多分上限を求める方が簡単ですか?
上限は、正確な実装に依存します(たとえば、使用されるバランスツリーの特定のバリアント)。たぶん、私たちがより良い支援をするために、なぜこの情報が必要なのか教えていただけますか?
私は最近この質問に自分で答える必要があり、64ビットモードのMSVC 2012でコンパイルしたstd :: mapを使用して小さなベンチマークプログラムを単に作成しました。
1億5,000万のノードが15 GBまで吸収されたマップは、8バイトのL、8バイトのR、8バイトのintキー、および8バイトのデータで、合計32バイトで吸収されますマップのメモリの約2/3内部ノードの場合、葉の1/3を残します。
個人的には、これは驚くほどメモリ効率が悪いことがわかりましたが、それはそれです。
これが便利な経験則になることを願っています。
PS:std :: mapのオーバーヘッドは、単一ノードのサイズAFAICTのオーバーヘッドです。
式はより似ています:
(sizeof(A) + sizeof(B) + factor) * N
ここで、factorはエントリごとのオーバーヘッドです。 C++マップは通常、赤黒木として実装されます。これらはバイナリツリーであるため、左右のノードには少なくとも2つのポインタがあります。いくつかの実装のものもあります-おそらく親ポインターと「カラー」インジケーターなので、要因は次のようなものかもしれません
(sizeof( RBNode *) * 3 + 1) / 2
ただし、これはすべて実装に大きく依存します。実際に独自のライブラリ実装のコードを調べる必要があるかどうかを確認するためです。