Golang中的字符串内存使用情况

时间:2018-10-17 09:42:05

标签: string go memory size

我正在使用 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 只有一个字母一样?

1 个答案:

答案 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)的整个备用数组。