Sobes.tech
Middle+

Wie viele Bytes benötigt eine Karte (Map) in Golang?

sobes.tech KI

Antwort von AI

Die Größe der Map in Golang ist nicht fest und hängt von vielen Faktoren ab:

  • Anzahl der Elemente: Je mehr Elemente, desto mehr Speicher wird für deren Speicherung benötigt.
  • Größe der Schlüssel und Werte: Jeder Schlüssel und Wert belegt Speicher. Strings, Slices, Strukturen – all dies beeinflusst die Gesamtsgröße.
  • Servicedaten der Struktur hmap: eine Map ist ein Zeiger auf die Struktur hmap. Diese Struktur enthält Servicefelder:
    • Zähler der Elemente
    • Zeiger auf die Buckets
    • Zähler der Migrationen (Wachsen/Schrumpfen)
    • und andere Metadaten
  • Größe der Buckets: Elemente werden in Buckets gespeichert. Jeder Bucket hat eine feste Größe (normalerweise 8 Schlüssel-Wert-Paare), aber die Daten der Schlüssel und Werte werden separat gespeichert, auf die die Zeiger in den Buckets verweisen. Buckets können ungenutzten Raum enthalten.
  • Füllgrad: Beim Hinzufügen von Elementen kann die Map neu gehasht werden und die Anzahl der Buckets erhöht werden, was die Zuweisung neuen Speichers erfordert.
  • Speicheralignment: Go richtet die Daten im Speicher aus, was zu zusätzlichen Bytes führen kann, um einen korrekten Zugriff zu gewährleisten.

Daher ist es unmöglich, eine genaue Byte-Anzahl anzugeben, da sie sich dynamisch ändert, abhängig vom Inhalt und Wachstum der Map. Es kann eine untere Grenze (Speicher für hmap und den ersten Bucket) und eine obere Grenze (Summe der Größen der Schlüssel, Werte, Buckets und Metadaten) geschätzt werden, aber die genaue Größe wird vom Go-Runtime bestimmt.

Zur Schätzung der Größe kann das Paket unsafe oder Debugging-Tools verwendet werden, aber sie geben die Größe zu einem bestimmten Zeitpunkt für einen bestimmten Inhalt an.

// Beispiel für eine vereinfachte hmap-Struktur
// Die Struktur ist nicht für den direkten Gebrauch bestimmt
// und ihre Felder können zwischen Go-Versionen variieren.
type hmap struct {
	// Das Format des hmap ist in ../runtime/map.go beschrieben.
	// Es ist eine Hashtabelle mit Buckets, die aus dem Go-Heap alloziert werden.
	// hmap.buckets zeigt auf das Slice der Buckets (kann nil sein).
	// Jeder Bucket ist ein Array von hmap.B entries, wobei B die Bucket-Größe ist.
	// Ein Bucket-Eintrag speichert den Schlüssel und den Wert für einen einzelnen Map-Eintrag,
	// plus ein tophash-Byte. Schlüssel und Werte werden im selben
	// Bucket-Eintrag gespeichert, wobei die Werte den Schlüsseln folgen.
	// Wenn Schlüssel-/Wertgrößen groß sind, werden sie indirekt in
	// Overflow-Buckets geschrieben, beginnend mit Overflow-Pointern in den
	// Haupt-Buckets.

	count     int // Anzahl der lebenden Zellen; ist != 0, wenn Map Einträge hat
	flags     uint8
	B         uint8  // log_2 der Anzahl der Buckets (kann bis zu 2^B Einträge enthalten)
	noverflow uint16 // ungefähre Anzahl der Overflow-Buckets
	hash0     uint32 // Hash-Seed

	buckets    unsafe.Pointer // Array von 2^B Buckets, im Heap alloziert
	oldbuckets unsafe.Pointer // vorheriges Array von 2^B Buckets, im Heap alloziert

	nevacuate uintptr // Fortschrittszähler für Evakuierung (Buckets verschoben in den neuen)

	// Wahr, wenn Schlüssel- oder Werttyp Zeiger enthält, die gescannt werden müssen
	keysize  uint8 // Größe des Schlüsseltyps
	valuesize uint8 // Größe des Werttyps
	elemsize  uint16 // Größe von Schlüssel + Wert (für In-Place-Speicherung)

	// Zeiger auf eine Slice von Overflow-Buckets, im Heap alloziert
	overflow *[]*bmap
}

// Beispiel für eine vereinfachte bmap-Struktur
// Bucket-Typ.
type bmap struct {
	// Das Layout eines Buckets ist komplex.
	// Siehe src/runtime/hashmap.go für Details.
	tophash [8]uint8 // 8 tophash Bytes (ein pro Schlüssel-Wert-Paar)
	// gefolgt von Schlüsseln und dann Werten
	// gefolgt von einem Overflow-Pointer
}