Sobes.tech
Middle+

Quantos bytes ocupa um mapa (mapa) em Golang?

sobes.tech IA

Resposta da IA

O tamanho do mapa em Golang não é fixo e depende de muitos fatores:

  • Número de elementos: Quanto mais elementos, mais memória é necessária para armazená-los.
  • Tamanho das chaves e valores: Cada chave e valor ocupa memória. Strings, slices, estruturas, tudo isso influencia o tamanho total.
  • Dados de serviço da estrutura hmap: um map é um ponteiro para a estrutura hmap. Esta estrutura contém campos de serviço:
    • contador de elementos
    • ponteiros para os buckets
    • contador de migrações (crescer/diminuir)
    • e outros metadados
  • Tamanho dos buckets: Os elementos são armazenados em buckets. Cada bucket tem um tamanho fixo (normalmente 8 pares chave-valor), mas os dados de chaves e valores são armazenados separadamente, apontados pelos ponteiros dentro do bucket. Os buckets podem conter espaço não utilizado.
  • Densidade de preenchimento: Ao adicionar elementos, o map pode re-hash e aumentar o número de buckets, o que requer alocação de nova memória.
  • Alinhamento de memória: Go alinha os dados na memória, o que pode levar a bytes adicionais para garantir acesso correto.

Portanto, não é possível determinar um tamanho exato em bytes, pois ele muda dinamicamente dependendo do conteúdo e do crescimento do map. Pode-se estimar um limite inferior (memória para hmap e o primeiro bucket) e um limite superior (soma dos tamanhos de chaves, valores, buckets e metadados), mas o tamanho exato é determinado pelo runtime do Go.

Para estimar o tamanho, pode-se usar o pacote unsafe ou ferramentas de depuração, mas eles fornecerão o tamanho em um momento específico para um conteúdo específico.

// Exemplo de estrutura hmap (simplificada)
// A estrutura não é destinada ao uso direto
// e seus campos podem mudar entre versões do Go.
type hmap struct {
	// O formato do hmap é descrito em ../runtime/map.go.
	// É uma tabela hash com buckets alocados a partir do heap do Go.
	// hmap.buckets aponta para o slice de buckets (pode ser nil).
	// Cada bucket é um array de entradas hmap.B, onde B é o tamanho do bucket.
	// Uma entrada de bucket armazena a chave e o valor para uma única entrada do mapa,
	// além de um byte tophash. Chaves e valores são armazenados na mesma
	// entrada de bucket, com os valores seguindo as chaves.
	// Se os tamanhos de chave/valor forem grandes, são escritos indiretamente em
	// buckets de overflow, começando por ponteiros de overflow nos
	// buckets principais.

	count     int // número de células vivas; não é zero se o mapa tiver entradas
	flags     uint8
	B         uint8  // log_2 do número de buckets (pode conter até 2^B entradas)
	noverflow uint16 // número aproximado de buckets de overflow
	hash0     uint32 // semente de hash

	buckets    unsafe.Pointer // array de 2^B buckets, alocado no heap
	oldbuckets unsafe.Pointer // array anterior de 2^B buckets, alocado no heap

	nevacuate uintptr // contador de progresso para evacuação (buckets movidos para o novo)

	// verdadeiro quando o tipo de chave ou valor tem ponteiros que precisam de análise
	keysize  uint8 // tamanho do tipo de chave
	valuesize uint8 // tamanho do tipo de valor
	elemsize  uint16 // tamanho de chave + valor (para armazenamento in-place)

	// ponteiro para uma slice de buckets de overflow, alocado no heap
	overflow *[]*bmap
}

// Exemplo de estrutura bmap (simplificada)
// Tipo de bucket.
type bmap struct {
	// A disposição de um bucket é complexa.
	// Veja src/runtime/hashmap.go para detalhes.
	tophash [8]uint8 // 8 bytes de tophash (um por par chave-valor)
	// seguido por chaves e depois valores
	// seguido por um ponteiro de overflow
}