我正在使用 map [string] string 优化代码,其中地图的值仅为“ A”或“ B”。因此,我认为显然 map [string] bool 会更好,因为地图可容纳约5000万个元素。
var a = "a"
var a2 = "Why This ultra long string take the same amount of space in memory as 'a'"
var b = true
var c map[string]string
var d map[string]bool
c["t"] = "A"
d["t"] = true
fmt.Printf("a: %T, %d\n", a, unsafe.Sizeof(a))
fmt.Printf("a2: %T, %d\n", a2, unsafe.Sizeof(a2))
fmt.Printf("b: %T, %d\n", b, unsafe.Sizeof(b))
fmt.Printf("c: %T, %d\n", c, unsafe.Sizeof(c))
fmt.Printf("d: %T, %d\n", d, unsafe.Sizeof(d))
fmt.Printf("c: %T, %d\n", c, unsafe.Sizeof(c["t"]))
fmt.Printf("d: %T, %d\n", d, unsafe.Sizeof(d["t"]))
结果是:
a: string, 8
a2: string, 8
b: bool, 1
c: map[string]string, 4
d: map[string]bool, 4
c2: map[string]string, 8
d2: map[string]bool, 1
在测试时,我发现有些奇怪,为什么带有很长字符串的 a2 使用8个字节,与 a 只有一个字母一样?
答案 0 :(得分:5)
unsafe.Sizeof()
不会递归地进入数据结构,它只是报告所传递值的“浅”大小。引用其文档:
大小不包括x可能引用的任何内存。例如,如果x是切片,则Sizeof返回切片描述符的大小,而不是切片所引用的内存的大小
Go中的地图被实现为指针,因此compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
将报告该指针的大小。
Go中的字符串只是包含指针和长度的标头。参见reflect.StringHeader
:
unsafe.Sizeof(somemap)
因此type StringHeader struct {
Data uintptr
Len int
}
将报告上述结构的大小,而与unsafe.Sizeof(somestring)
值(即string
字段的值)的长度无关。
要获取地图的实际内存需求(“较深”),请参见How much memory do golang maps reserve?和How to get memory size of variable in Golang?
Go将Len
值的UTF-8编码字节序列存储在内存中。内置函数len()
报告string
的字节长度,因此
基本上,在内存中存储string
值所需的内存是:
string
也不要忘记,可以通过切片另一个更大的字符串来构造var str string = "some string"
stringSize := len(str) + unsafe.Sizeof(str)
值,因此,即使不再引用原始字符串(因此不再需要),也将使用更大的支持数组对于较小的字符串切片,仍然需要保留在内存中。
例如:
string
这里,即使s := "some loooooooong string"
s2 := s[:2]
的内存需求为s2
,仍将保留len(s2) + unsafe.Sizeof(str) = 2 + unsafe.Sizeof(str)
的整个备用数组。