Go语言 为什么一个空切片有24个字节?

ykejflvf  于 2022-12-16  发布在  Go
关注(0)|答案(2)|浏览(162)

我想了解当用make([]int, 0)创建一个空切片时会发生什么。

emptySlice := make([]int, 0)
fmt.Println(len(emptySlice))
fmt.Println(cap(emptySlice))
fmt.Println(unsafe.Sizeof(emptySlice))

大小和容量的回报是明显的,都是0,但是切片的大小是24字节,为什么?
24字节应该是3 int64,对吗?一个24字节的切片的内部数组应该如下所示:[3]int{},那么为什么一个空切片具有24个字节?

5lwkijsr

5lwkijsr1#

如果您阅读了unsafe.Sizeof的文档,它会解释这里发生了什么:
该大小不包括x可能引用的任何内存。例如,如果x是一个切片,则Sizeof返回切片描述符的大小,而不是切片引用的内存大小。
Go语言中所有数据类型的大小都是静态的,即使切片的元素数量是动态的,也不能反映在数据类型的大小上,因为那样的话数据类型就不是静态的了。
“切片描述符”,就像名字所暗示的那样,是描述一个切片的所有数据。这也是实际存储在切片变量中的内容。
Go语言中的切片有3个属性:基础数组(内存地址)、切片的长度(内存偏移量)和切片的容量(内存偏移量)。在64位应用程序中,内存地址和偏移量往往存储为64位(8字节)值。这就是您看到大小为24(= 3 * 8)字节的原因。

hc2pp10m

hc2pp10m2#

unsafe.Sizeof是 * 对象在内存中的大小 ,与C和C++中的sizeof完全相同。
一个切片有 size,但也有 resize 的能力,所以最大的调整大小的能力也必须存储在某个地方,但可调整大小也意味着它不能是静态数组,而是需要存储一个指向其他数组(可能是动态分配的)的指针
整个过程意味着它需要存储它的
**{开始,end,last valid index }{ begin,size,capacity }***,这是一个3值元组,这意味着在64位平台上,它在内存中的表示至少是3×8字节,除非您希望将最大大小和容量限制为远小于264字节
在许多具有相同动态大小调整功能的C++类型中,情况完全相同,例如std::stringstd::vector也是24字节类型,尽管在某些实现中,由于对齐原因添加了8字节的填充,从而导致32字节的字符串类型。

事实上golang的strings.Builder是最接近C++的std::string的,它的大小是32字节。

相关问题