Sobes.tech
Middle+

Hoeveel bytes neemt een kaart (map) in Golang in beslag?

sobes.tech AI

Antwoord van AI

De grootte van een map in Golang is niet vast en hangt af van veel factoren:

  • Aantal elementen: Hoe meer elementen, hoe meer geheugen nodig is om ze op te slaan.
  • Grootte van sleutels en waarden: Elke sleutel en waarde neemt geheugen in beslag. Strings, slices, structuren – dit alles beïnvloedt de totale grootte.
  • Servicedata van de hmap structuur: een map is een pointer naar de hmap structuur. Deze structuur bevat servicemeldingen:
    • teller van elementen
    • pointers naar de buckets
    • migratie teller (groei/krimp)
    • en andere metadata
  • Grootte van de buckets: Elementen worden opgeslagen in buckets. Elke bucket heeft een vaste grootte (meestal 8 sleutel-waarde paren), maar de gegevens van sleutels en waarden worden apart opgeslagen, waarnaar de pointers in de bucket verwijzen. Buckets kunnen onbenutte ruimte bevatten.
  • Vullingsdichtheid: Bij het toevoegen van elementen kan de map opnieuw worden gehasht en het aantal buckets worden verhoogd, wat het toewijzen van nieuwe geheugen vereist.
  • Geheugenuitlijning: Go uitlijnt gegevens in het geheugen, wat kan leiden tot extra bytes om correcte toegang te garanderen.

Daarom is het niet mogelijk om een exacte hoeveelheid bytes te geven, omdat deze dynamisch verandert afhankelijk van de inhoud en de groei van de map. Een ondergrens (geheugen voor hmap en de eerste bucket) en een bovengrens (som van de groottes van sleutels, waarden, buckets en metadata) kunnen worden geschat, maar de exacte grootte wordt bepaald door de Go-runtime.

Om de grootte te schatten, kan het unsafe pakket of debugging tools worden gebruikt, maar deze geven de grootte op een specifiek moment voor een specifieke inhoud.

// Voorbeeld van een vereenvoudigde `hmap` structuur
// Deze structuur is niet bedoeld voor direct gebruik
// en haar velden kunnen veranderen tussen versies van Go.
type hmap struct {
	// Het formaat van hmap wordt beschreven in ../runtime/map.go.
	// Het is een hashtabel met buckets die uit de Go-heap zijn toegewezen.
	// hmap.buckets wijst naar de slice van buckets (kan nil zijn).
	// Elke bucket is een array van hmap.B entries, waarbij B de bucket grootte is.
	// Een bucket entry slaat de sleutel en waarde op voor een enkele map entry,
	// plus een tophash byte. Sleutels en waarden worden in dezelfde
	// bucket entry opgeslagen, met de waarden die volgen op de sleutels.
	// Als de groottes van sleutel/waarde groot zijn, worden ze indirect geschreven in
	// overflow buckets, beginnend via overflow pointers in de hoofd-buckets.

	count     int // aantal levende cellen; sterk != 0 als map entries heeft
	flags     uint8
	B         uint8  // log_2 van het aantal buckets (kan tot 2^B entries bevatten)
	noverflow uint16 // geschatte aantal overflow buckets
	hash0     uint32 // hash seed

	buckets    unsafe.Pointer // array van 2^B buckets, gealloceerd op de heap
	oldbuckets unsafe.Pointer // vorige array van 2^B buckets, gealloceerd op de heap

	nevacuate uintptr // voortgangsteller voor evacuatie (buckets verplaatst naar nieuw)

	// waar wanneer de sleutel- of waarde type pointers heeft die gescand moeten worden
	keysize  uint8 // grootte van het sleuteltype
	valuesize uint8 // grootte van het waardetype
	elemsize  uint16 // grootte van sleutel + waarde (voor in-place opslag)

	// pointer naar een slice van overflow buckets, gealloceerd op de heap
	overflow *[]*bmap
}

// Voorbeeld van een vereenvoudigde bmap structuur
// Bucket type.
type bmap struct {
	// De lay-out van een bucket is complex.
	// Zie src/runtime/hashmap.go voor details.
	tophash [8]uint8 // 8 tophash bytes (één per key-value paar)
	// gevolgd door sleutels en vervolgens waarden
	// gevolgd door een overflow pointer
}