GoLang - 内存分配 - []字节与字符串

GoLang - memory allocation - []byte vs string

在下面的代码中:

c := "fool"
d := []byte("fool")
fmt.Printf("c: %T, %d\n", c, unsafe.Sizeof(c)) // 16 bytes
fmt.Printf("d: %T, %d\n", d, unsafe.Sizeof(d)) // 24 bytes

为了确定从 CloudFoundry 接收 JSON 数据所需的数据类型,正在测试上面的示例代码以了解 []bytestring 类型的内存分配。


string 类型变量 c 的预期大小为 1 字节 x 4 ascii 编码字母 = 4 字节,但大小显示为 16 字节。

对于byte类型的变量d,GO将字符串作为字符串字面量嵌入到可执行程序中。它在运行时使用 runtime.stringtoslicebyte 函数将字符串文字转换为字节切片。像... []byte{102, 111, 111, 108}

byte 类型变量 d 的预期大小再次为 1 字节 x 4 个 ascii 值 = 4 字节,但变量 d 的大小显示为 24 字节,因为它是底层数组容量。


为什么两个变量的大小都不是4字节?

Go中的切片和字符串都是struct-like headers:

reflect.SliceHeader:

type SliceHeader struct {
        Data uintptr
        Len  int
        Cap  int
}

reflect.StringHeader:

type StringHeader struct {
        Data uintptr
        Len  int
}

unsafe.Sizeof() 报告的大小是这些 headers 的大小,不包括指向数组的大小:

Sizeof takes an expression x of any type and returns the size in bytes of a hypothetical variable v as if v was declared via var v = x. 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 的内置测试和基准测试框架。有关详细信息,请参阅 How to get memory size of variable in Go?

具体的字符串,请参见String memory usage in Golangstring 值所需的完整内存可以这样计算:

var str string = "some string"

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