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?
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.
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%
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?
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.
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.