web-dev-qa-db-ja.com

std :: mapのメモリ使用量をどのように推定できますか?

たとえば、私は既知のsizeof(A)とsizeof(B)を持つs​​td :: mapを持っていますが、mapにはN個のエントリがあります。そのメモリ使用量をどのように推定しますか?それは次のようなものだと思います

(sizeof(A) + sizeof(B)) * N * factor

しかし、要因は何ですか?多分違う式?

多分上限を求める方が簡単ですか?

43
Drakosha

推定値は

_(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)になります。上の図には、マップの要素を格納するために使用されるメモリ管理構造のオーバーヘッドも追加する必要があります。

さまざまな大規模なコレクションのコードのメモリ消費量を測定することで、見積もりにたどり着く方がおそらく簡単です。

35

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%
18
Xavier Nodet

ランタイムメモリのフットプリントを本当に知りたい場合は、カスタムアロケータを使用して、マップの作成時に渡します。 Josuttisの本と彼の this ページを参照してください(カスタムアロケーターの場合)。

多分上限を求める方が簡単ですか?

上限は、正確な実装に依存します(たとえば、使用されるバランスツリーの特定のバリアント)。たぶん、私たちがより良い支援をするために、なぜこの情報が必要なのか教えていただけますか?

14
dirkgently

私は最近この質問に自分で答える必要があり、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のオーバーヘッドです。

7
user2548100

式はより似ています:

(sizeof(A) + sizeof(B) + factor) * N

ここで、factorはエントリごとのオーバーヘッドです。 C++マップは通常、赤黒木として実装されます。これらはバイナリツリーであるため、左右のノードには少なくとも2つのポインタがあります。いくつかの実装のものもあります-おそらく親ポインターと「カラー」インジケーターなので、要因は次のようなものかもしれません

(sizeof( RBNode *) * 3 + 1) / 2

ただし、これはすべて実装に大きく依存します。実際に独自のライブラリ実装のコードを調べる必要があるかどうかを確認するためです。

0
anon