为映射键分配了多少内存?即 map[uint16]uint16 是每个键 2 个字节还是存储为 uint32/64 无论如何?

hel*_*ase 1 memory dictionary go

我想知道 uint8 或 uint16 Go 映射键是否将存储为 1/2 字节,或者它们将具有 uint32/64 内存分配,而不管指定较小的值?

icz*_*cza 6

Map 是 Go 中的 hashmap,它们的内部结构非常重要。常识告诉密钥大小应该有所作为,但由于这不在语言规范中,请自行衡量。

检查如何在 Go 中获取变量的内存大小?关于如何测量任意变量的大小。

例如创建一个测试:

const size = 250

func getMap8(size int) map[uint8]uint16 {
    m := make(map[uint8]uint16, size)
    for i := uint8(0); i < uint8(size); i++ {
        m[i] = uint16(i)
    }
    return m
}

func getMap16(size int) map[uint16]uint16 {
    m := make(map[uint16]uint16, size)
    for i := uint16(0); i < uint16(size); i++ {
        m[i] = i
    }
    return m
}

func getMap32(size int) map[uint32]uint16 {
    m := make(map[uint32]uint16, size)
    for i := uint32(0); i < uint32(size); i++ {
        m[i] = uint16(i)
    }
    return m
}

func getMap64(size int) map[uint64]uint16 {
    m := make(map[uint64]uint16, size)
    for i := uint64(0); i < uint64(size); i++ {
        m[i] = uint16(i)
    }
    return m
}

func Benchmark8(b *testing.B) {
    for n := 0; n < b.N; n++ {
        getMap8(size)
    }
}

func Benchmark16(b *testing.B) {
    for n := 0; n < b.N; n++ {
        getMap16(size)
    }
}

func Benchmark32(b *testing.B) {
    for n := 0; n < b.N; n++ {
        getMap32(size)
    }
}

func Benchmark64(b *testing.B) {
    for n := 0; n < b.N; n++ {
        getMap64(size)
    }
}
Run Code Online (Sandbox Code Playgroud)

运行它go test -bench . -benchmem,输出是:

Benchmark8-8      95862    11210 ns/op   3188 B/op       4 allocs/op
Benchmark16-8    107731    11017 ns/op   3572 B/op       4 allocs/op
Benchmark32-8    150126     8496 ns/op   4980 B/op       4 allocs/op
Benchmark64-8    144655     8959 ns/op   6644 B/op       4 allocs/op
Run Code Online (Sandbox Code Playgroud)

所以如果key的大小越小,map的大小确实越小,但显然key和value的大小共同决定了最终的大小。

map[uint8]uint16250个条目类型的映射大小约为3188字节,uint16键类型映射为3572字节,uint32键类型映射为4980字节,uint64键类型映射为6644字节。