Golang中的字符串内存使用情况 [英] String memory usage in Golang

查看:1326
本文介绍了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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆