Golang 中的字符串内存使用

标签 string go memory size

我正在使用 ma​​p[string]string 优化代码,其中映射的值只有“A”或“B”。所以我认为 ma​​p[string]bool 显然更好,因为 map 包含大约 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 一样?

最佳答案

unsafe.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) 将报告该指针的大小。

Go 中的字符串只是包含指针和长度的 header 。参见 reflect.StringHeader :

type StringHeader struct {
        Data uintptr
        Len  int
}

因此 unsafe.Sizeof(somestring) 将报告上述结构的大小,它与 string 值的长度无关(这是Len 字段)。

要获得 map 的实际内存需求(“深度”),请参阅 How much memory do golang maps reserve?还有How to get memory size of variable in Go?

Go 将 string 值的 UTF-8 编码字节序列存储在内存中。内置函数 len()报告 string 的字节长度,所以 基本上,在内存中存储一​​个 string 值所需的内存是:

var str string = "some string"

stringSize := len(str) + int(unsafe.Sizeof(str))

另外不要忘记 string 值可以通过 slice 另一个更大的字符串来构造,因此即使不再引用原始字符串(因此不再需要),更大的对于较小的字符串 slice ,仍然需要将后备数组保存在内存中。

例如:

s := "some loooooooong string"
s2 := s[:2]

这里,即使 s2 的内存要求是 len(s2) + unsafe.Sizeof(str) = 2 + unsafe.Sizeof(str),仍然, s 的整个后备数组将被保留。

关于Golang 中的字符串内存使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52851788/

相关文章:

templates - 什么是正确的文件扩展名或缩写。对于 golang 的文本/模板?

c - Windows 和 Linux 操作系统的内存布局有什么不同吗?

ios - 在 UIScrollView 的 subview 中绘制网格分配大量内存

.net - 如何使用 "For Each"循环修改字符串?

c# - 使用 List<string>.Any() 查找字符串是否包含项目以及查找匹配项目?

go - 在 Go 中的文件顶部创建 channel

php - fatal error : Allowed Memory Size of 134217728 Bytes Exhausted (CodeIgniter + XML-RPC)

c - 替换字符串中的标记

c# - 按字符拆分字符串并在C#中用逗号分隔

go - 在一个函数中创建结构以在另一个函数中使用