Given a map allocation where the initial space is not specified, for example:
foo := make(map[string]int)
The documentation suggests that the memory allocation here is implementation dependent. So (how) can I tell how much memory my implementation is allocating to this map?
You may use the Go testing tool to measure size of arbitrary complex data structures. This is detailed in this answer: How to get variable memory size of variable in golang?
To measure the size of a map created by make(map[string]int)
, use the following benchmark function:
var x map[string]int
func BenchmarkEmptyMap(b *testing.B) {
for i := 0; i < b.N; i++ {
x = make(map[string]int)
}
}
Executing with
go test -bench . -benchmem
The result is:
BenchmarkEmptyMap-4 20000000 110 ns/op 48 B/op 1 allocs/op
So the answer is on my 64-bit architecture: 48 bytes.
As hinted, size may depend on architecture. Also size may depend on the initial capacity you may pass to make()
, as you can see in this example:
func BenchmarkEmptyMapCap100(b *testing.B) {
for i := 0; i < b.N; i++ {
x = make(map[string]int, 100)
}
}
Output:
BenchmarkEmptyMapCap100-4 1000000 1783 ns/op 4176 B/op 3 allocs/op
A map of type map[string]int
with an initial capacity of 100 now requires 4176 bytes (on 64-bit arch).
The default initial capacity is around 7 if not specified explicitly.
If you look at the source of Go's map type, you will see, that a map consists of a header (type hmap
) and an array of buckets (type bmap
). When you create a new map and don't specify the initial space (hint
), only one bucket is created.
A header consists of several fields:
1 * int
,
2 * uint8
,
1 * uint16
,
1 * uint32
,
2 * unsafe.Pointer
,
1 * uintptr
.
Size of the types int
, uintptr
, and unsafe.Pointer
equals the size of a word (8 bytes on 64 bit machines).
A bucket consists of an array of 8 * uint8
.
This gives a total of 40 + 8 = 48 bytes (64 bit architecture)