Sobes.tech
Middle+

Quelle est la taille en octets d'une carte (map) en Golang?

sobes.tech IA

Réponse de l'IA

La taille de la map en Golang n'est pas fixe et dépend de nombreux facteurs:

  • Nombre d'éléments: Plus il y a d'éléments, plus il faut de mémoire pour les stocker.
  • Taille des clés et valeurs: Chaque clé et valeur occupe de la mémoire. Les chaînes, slices, structures, tout cela influence la taille totale.
  • Données de service de la structure hmap: une map est un pointeur vers la structure hmap. Cette structure contient des champs de service:
    • compteur d'éléments
    • pointeurs vers les buckets
    • compteur de migrations (agrandissement/réduction)
    • et autres métadonnées
  • Taille des buckets: Les éléments sont stockés dans des buckets. Chaque bucket a une taille fixe (habituellement 8 paires clé-valeur), mais les données de clés et valeurs sont stockées séparément, pointées par les pointeurs dans le bucket. Les buckets peuvent contenir de l'espace inutilisé.
  • Densité de remplissage: Lors de l'ajout d'éléments, la map peut se re-hasher et augmenter le nombre de buckets, ce qui nécessite d'allouer de la mémoire supplémentaire.
  • Alignement mémoire: Go aligne les données en mémoire, ce qui peut entraîner des octets supplémentaires pour assurer un accès correct.

Ainsi, il est impossible de donner une taille précise en octets, car elle change dynamiquement en fonction du contenu et de la croissance de la map. On peut estimer une limite inférieure (mémoire pour hmap et le premier bucket) et une limite supérieure (somme des tailles des clés, valeurs, buckets et métadonnées), mais la taille exacte est déterminée par le runtime de Go.

Pour estimer la taille, on peut utiliser le package unsafe ou des outils de débogage, mais ils donneront la taille à un moment précis pour un contenu précis.

// Exemple de structure hmap (simplifiée)
// La structure n'est pas destinée à un usage direct
// et ses champs peuvent changer entre les versions de Go.
type hmap struct {
	// La disposition du hmap est décrite dans ../runtime/map.go.
	// C'est une table de hachage avec des buckets alloués depuis le tas de Go.
	// hmap.buckets pointe vers le slice de buckets (peut être nil).
	// Chaque bucket est un tableau d'entrées hmap.B, où B est la taille du bucket.
	// Une entrée de bucket stocke la clé et la valeur pour une seule entrée de la map,
	// plus un byte tophash. Les clés et valeurs sont stockées dans la même
	// entrée de bucket, avec les valeurs suivant les clés.
	// Si les tailles de clé/valeur sont grandes, elles sont écrites indirectement dans
	// des buckets de débordement, en commençant par des pointeurs de débordement dans
	// les buckets principaux.

	count     int // nombre de cellules vivantes; pas égal à 0 si la map a des entrées
	flags     uint8
	B         uint8  // log_2 du nombre de buckets (peut contenir jusqu'à 2^B entrées)
	noverflow uint16 // nombre approximatif de buckets de débordement
	hash0     uint32 // graine de hachage

	buckets    unsafe.Pointer // tableau de 2^B buckets, alloué sur le tas
	oldbuckets unsafe.Pointer // tableau précédent de 2^B buckets, alloué sur le tas

	nevacuate uintptr // compteur de progression pour l'évacuation (buckets déplacés vers le nouveau)

	// vrai lorsque le type de clé ou de valeur a des pointeurs nécessitant une analyse
	keysize  uint8 // taille du type de clé
	valuesize uint8 // taille du type de valeur
	elemsize  uint16 // taille de clé + valeur (pour stockage en place)

	// pointeur vers une slice de buckets de débordement, alloué sur le tas
	overflow *[]*bmap
}

// Exemple de structure bmap (simplifiée)
// Type de bucket.
type bmap struct {
	// La disposition d'un bucket est complexe.
	// Voir src/runtime/hashmap.go pour les détails.
	tophash [8]uint8 // 8 bytes de tophash (un par paire clé-valeur)
	// suivi par clés et puis valeurs
	// suivi par un pointeur de débordement
}