Golang中的字符串内存使用情况 [英] String memory usage in Golang
问题描述
我正在使用 map [string] string 优化代码,其中地图的值仅为"A"或"B".因此,我认为显然 map [string] bool 会更好,因为地图可容纳约5000万个元素.
I was optimising a code using a map[string]string where the value of the map was only either "A" or "B". So I thought Obviously a map[string]bool was way better as the map hold around 50 millions elements.
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 只有一个字母一样?
While testing I found something weird, why a2 with a really long string use 8 bytes, same as a wich has only one letter ?
推荐答案
unsafe.Sizeof()
不会递归地进入数据结构,它只是报告传递的值的浅"大小.引用其文档:
unsafe.Sizeof()
does not recursively go into data structures, it just reports the "shallow" size of the value passed. Quoting from its doc:
大小不包括x可能引用的任何内存.例如,如果x是切片,则Sizeof返回切片描述符的大小,而不是切片所引用的内存的大小
The size does not include any memory possibly referenced by x. For instance, if x is a slice, Sizeof returns the size of the slice descriptor, not the size of the memory referenced by the slice.
Go中的地图被实现为指针,因此unsafe.Sizeof(somemap)
将报告该指针的大小.
Maps in Go are implemented as pointers, so unsafe.Sizeof(somemap)
will report the size of that pointer.
Go中的字符串只是包含指针和长度的标头.参见 reflect.StringHeader
:
Strings in Go are just headers containing a pointer and a length. See reflect.StringHeader
:
type StringHeader struct {
Data uintptr
Len int
}
因此unsafe.Sizeof(somestring)
将报告上述结构的大小,而与string
值(即Len
字段的值)的长度无关.
So unsafe.Sizeof(somestring)
will report the size of the above struct, which is independent of the length of the string
value (which is the value of the Len
field).
要获取地图的实际内存需求(深度"),请参见如何在Golang中获取变量的内存大小?
To get the actual memory requirement of a map ("deeply"), see How much memory do golang maps reserve? and also How to get memory size of variable in Golang?
Go将string
值的UTF-8编码字节序列存储在内存中.内置函数 len()
报告string
的字节长度,因此
基本上,在内存中存储string
值所需的内存是:
Go stores the UTF-8 encoded byte sequences of string
values in memory. The builtin function len()
reports the byte-length of a string
, so
basically the memory required to store a string
value in memory is:
var str string = "some string"
stringSize := len(str) + unsafe.Sizeof(str)
也不要忘记,可以通过切片另一个更大的字符串来构造string
值,因此,即使不再引用原始字符串(因此不再需要),也仍然会使用更大的支持数组需要保留在内存中以用于较小的字符串切片.
Also don't forget that a string
value may be constructed by slicing another, bigger string, and thus even if the original string is no longer referenced (and thus no longer needed), the bigger backing array will still be required to kept in memory for the smaller string slice.
例如:
s := "some loooooooong string"
s2 := s[:2]
这里,即使s2
的内存要求为len(s2) + unsafe.Sizeof(str) = 2 + unsafe.Sizeof(str)
,仍然会保留s
的整个后备数组.
Here, even though memory requirement for s2
would be len(s2) + unsafe.Sizeof(str) = 2 + unsafe.Sizeof(str)
, still, the whole backing array of s
will be retained.
这篇关于Golang中的字符串内存使用情况的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!