Sobes.tech
Middle+

Kolik bajtů zabírá mapa (mapa) v Golang?

sobes.tech AI

Odpověď od AI

Velikost mapy v Golangu není pevná a závisí na mnoha faktorech:

  • Počet prvků: Čím více prvků, tím více paměti je potřeba pro jejich uložení.
  • Velikost klíčů a hodnot: Každý klíč a hodnota zabírá paměť. Řetězce, slices, struktury — to vše ovlivňuje celkovou velikost.
  • Pomocná data struktury hmap: map je ukazatel na strukturu hmap. Tato struktura obsahuje pomocná pole:
    • čítač prvků
    • ukazatele na koše (buckets)
    • čítač migrací (zvětšení/zmenšení)
    • a další metadata
  • Velikost košů (buckets): prvky jsou uloženy v koších. Každý koš má pevnou velikost (obvykle 8 párů klíč-hodnota), ale data klíčů a hodnot jsou uložena samostatně, na které ukazují ukazatele z koše. Koše mohou obsahovat nevyužitý prostor.
  • Hustota zaplnění: Při přidávání prvků se může map přehashovat a zvětšovat počet košů, což vyžaduje alokaci nové paměti.
  • Zarovnání paměti: Go zarovnává data v paměti, což může vést k přídavným bajtům pro zajištění správného přístupu.

Nelze přesně určit počet bajtů, protože se dynamicky mění v závislosti na obsahu a růstu mapy. Lze odhadnout spodní hranici (paměť pro hmap a první koš) a horní hranici (součet velikostí klíčů, hodnot, košů a pomocných dat), ale přesná velikost je určena runtime Go.

Pro odhad velikosti lze použít balíček unsafe nebo ladicí nástroje, ale ty poskytnou velikost v konkrétním okamžiku pro konkrétní obsah.

// Příklad struktury `hmap` (zjednodušený)
// Struktura není určena pro přímé použití
// a její pole se mohou měnit mezi verzemi Go.
type hmap struct {
	// Poznámka: formát `hmap` je popsán v ../runtime/map.go.
	// Je to hash tabulka s koši alokovanými z go heapu.
	// hmap.buckets ukazuje na slice košů (může být nil).
	// Každý koš je pole `hmap.B` s velikostí B.
	// Poloha v koši ukládá klíč a hodnotu pro jeden záznam mapy,
	// plus byte tophash. Klíče a hodnoty jsou uloženy ve stejném
	// záznamu koše, přičemž hodnoty následují klíče.
	// Pokud jsou velikosti klíče/hodnoty velké, zapisují se nepřímo do
	// overflow košů, začínajíc přes overflow ukazatele v hlavních koších.

	count     int // počet živých buněk; není rovno 0, pokud mapa má nějaké záznamy
	flags     uint8
	B         uint8  // log_2 počtu košů (může pojmout až 2^B záznamů)
	noverflow uint16 // přibližný počet overflow košů
	hash0     uint32 // hash seed

	buckets    unsafe.Pointer // pole košů 2^B, alokováno na haldě
	oldbuckets unsafe.Pointer // předchozí pole košů 2^B, alokováno na haldě

	nevacuate uintptr // čítač pokroku pro evakuaci (přesun košů do nových)

	// pravda, když typ klíče nebo hodnoty má ukazatele, které je třeba skenovat
	keysize  uint8 // velikost typu klíče
	valuesize uint8 // velikost typu hodnoty
	elemsize  uint16 // velikost klíč + hodnota (pro in-place uložení)

	// ukazatel na slice overflow košů, alokováno na haldě
	overflow *[]*bmap
}

// Příklad struktury `bmap` (zjednodušený)
// Typ koše.
type bmap struct {
	// Rozložení koše je složité.
	// Podrobnosti najdete v src/runtime/hashmap.go.
	tophash [8]uint8 // 8 bajtů tophash (jeden na pár kv)
	// následují klíče a pak hodnoty
	// následuje overflow ukazatel
}