pupuk / blog

My New Blog. Record & Share. Focus on PHP, MySQL, Javascript and Golang.
MIT License
9 stars 2 forks source link

Golang中的string,unsafe.Sizof(string)总是16个字节,为什么? #31

Open pupuk opened 3 years ago

pupuk commented 3 years ago

image image why? 这是因为string类型其实是一个结构体:

// StringHeader is the runtime representation of a string.
// It cannot be used safely or portably and its representation may
// change in a later release.
// Moreover, the Data field is not sufficient to guarantee the data
// it references will not be garbage collected, so programs must keep
// a separate, correctly typed pointer to the underlying data.
type StringHeader struct {
    Data uintptr
    Len  int
}

StirngHeader定义所在的源码 https://github.com/golang/go/blob/master/src/reflect/value.go

官方有说明: 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. 如果说x是一个切片,sizeof返回的大小是切片的描述符,而不是切片所指向的内存的大小,不会返回类型里面引用的大小。

Sizeof返回类型v本身数据所占用的字节数。返回值是“顶层”的数据占有的字节数。例如,若v是一个切片,它会返回该切片描述符的大小,而非该切片底层引用的内存的大小。

在64bit系统中,string对应的结构体就两个东西,指向真正寸字符串起始位置的指针(8个字节),字符串的字节长度(8个字节)

这也解释我心中的疑问:int数组内存是连续的,string数组(字符串有长有短)在内存中也是连续的么?答案是的。

举个例子:

func main() {
    arr := [...]string{"a", "abcdefg", "我是一名中华人民共和国的公民"}
    fmt.Println(unsafe.Sizeof(arr))
}

image 其内存分配应该是: image

同理

arr := []string{"a", "abcdefg", "我是一名中华人民共和国的公民", "XXYYZZ"}
fmt.Println(unsafe.Sizeof(arr))

结果是24,因为slice结构体有3个东西: Data uintptr Len int Cap int 所以不管是int的slice,srting构成的slice,还是map构成的slice,用unsafe.Sizeof(这个slice),在64bit系统中,结果永远是24.

数组

arr := [...]uint8{1, 35, 127}
fmt.Println(unsafe.Sizeof(arr))

结果是:3

arr := [...]uint8{1, 35, 127, 255}
fmt.Println(unsafe.Sizeof(arr))

结果是4

其它讲的好相关文章:

深度解密Go语言之unsafe Understand unsafe in GoLan 在 Go 中恰到好处的内存对齐

pupuk commented 3 years ago
m := map[string]int{
    "a": 97,
    "A": 65,
    " ": 32,
    "+": 43,
}

fmt.Println(m)
fmt.Println(unsafe.Sizeof(m))

image map的结果总是8