web-dev-qa-db-fra.com

Comment puis-je estimer l'utilisation de la mémoire de std :: map?

Par exemple, j'ai un std :: map avec une taille connue (A) et sizeof (B), tandis que la carte a N entrées à l'intérieur. Comment estimeriez-vous son utilisation de la mémoire? Je dirais que c'est quelque chose comme

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

Mais quel est le facteur? Formule différente peut-être?

Peut-être est-il plus facile de demander une limite supérieure?

43
Drakosha

L'estimation serait plus proche de

(sizeof(A) + sizeof(B) + ELEMENT_OVERHEAD) * N + CONTAINER_OVERHEAD

Il y a une surcharge pour chaque élément que vous ajoutez, et il y a aussi une surcharge fixe pour maintenir la structure de données utilisée pour la structure de données stockant la carte. Il s'agit généralement d'un arbre binaire, tel qu'un arbre rouge-noir . Par exemple, dans l'implémentation GCC C++ STL ELEMENT_OVERHEAD Serait sizeof(_Rb_tree_node_base) et CONTAINER_OVERHEAD Serait sizeof(_Rb_tree). À la figure ci-dessus, vous devez également ajouter les frais généraux des structures de gestion de la mémoire utilisées pour stocker les éléments de la carte.

Il est probablement plus facile d'arriver à une estimation en mesurant la consommation de mémoire de votre code pour diverses grandes collections.

35

Vous pouvez utiliser MemTrack , par Curtis Bartley. Il s'agit d'un allocateur de mémoire qui remplace celui par défaut et peut suivre l'utilisation de la mémoire jusqu'au type d'allocation.

Un exemple de sortie:

-----------------------
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

Si vous voulez vraiment connaître l'empreinte de la mémoire d'exécution, utilisez un allocateur personnalisé et transmettez-le lors de la création de la carte. Voir le livre de Josuttis et cette page de son (pour un allocateur personnalisé).

Peut-être est-il plus facile de demander une limite supérieure?

La limite supérieure dépendra de l'implémentation exacte (par exemple, la variante particulière d'arbre équilibré utilisée). Peut-être pouvez-vous nous dire pourquoi vous avez besoin de ces informations pour que nous puissions mieux vous aider?

14
dirkgently

J'ai récemment eu besoin de répondre à cette question pour moi-même et j'ai simplement écrit un petit programme de référence en utilisant std :: map que j'ai compilé sous MSVC 2012 en mode 64 bits.

Une carte avec 150 millions de nœuds absorbés ~ 15 Go, ce qui implique la clé de 8 octets L, 8 octets R, la clé int de 8 octets et les données de 8 octets, totalisant 32 octets, absorbés environ 2/3 de la mémoire de la carte pour les nœuds internes, en laissant 1/3 pour les feuilles.

Personnellement, j'ai trouvé que c'était une efficacité de mémoire étonnamment faible, mais c'est ce que c'est.

J'espère que cela en fait une règle pratique.

PS: Le surdébit d'une carte std :: est celui de la taille d'un seul nœud AFAICT.

7
user2548100

La formule ressemble plus à:

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

où facteur correspond aux frais généraux par entrée. Les cartes C++ sont généralement implémentées sous forme d'arbres rouge-noir. Ce sont des arbres binaires, il y aura donc au moins deux pointeurs pour les nœuds gauche/droit. Il y aura également des éléments d'implémentation - probablement un pointeur parent et un indicateur "couleur", donc le facteur peut être quelque chose comme

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

Cependant, tout cela dépend fortement de l'implémentation - pour vous assurer que vous devez vraiment examiner le code de votre propre implémentation de bibliothèque.

0
anon