我想了解当用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个字节?
2条答案
按热度按时间5lwkijsr1#
如果您阅读了
unsafe.Sizeof
的文档,它会解释这里发生了什么:该大小不包括x可能引用的任何内存。例如,如果x是一个切片,则Sizeof返回切片描述符的大小,而不是切片引用的内存大小。
Go语言中所有数据类型的大小都是静态的,即使切片的元素数量是动态的,也不能反映在数据类型的大小上,因为那样的话数据类型就不是静态的了。
“切片描述符”,就像名字所暗示的那样,是描述一个切片的所有数据。这也是实际存储在切片变量中的内容。
Go语言中的切片有3个属性:基础数组(内存地址)、切片的长度(内存偏移量)和切片的容量(内存偏移量)。在64位应用程序中,内存地址和偏移量往往存储为64位(8字节)值。这就是您看到大小为24(= 3 * 8)字节的原因。
hc2pp10m2#
unsafe.Sizeof
是 * 对象在内存中的大小 ,与C和C++中的sizeof
完全相同。一个切片有 size,但也有 resize 的能力,所以最大的调整大小的能力也必须存储在某个地方,但可调整大小也意味着它不能是静态数组,而是需要存储一个指向其他数组(可能是动态分配的)的指针
整个过程意味着它需要存储它的**{开始,end,last valid index }或{ begin,size,capacity }***,这是一个3值元组,这意味着在64位平台上,它在内存中的表示至少是3×8字节,除非您希望将最大大小和容量限制为远小于264字节
在许多具有相同动态大小调整功能的C++类型中,情况完全相同,例如
std::string
或std::vector
也是24字节类型,尽管在某些实现中,由于对齐原因添加了8字节的填充,从而导致32字节的字符串类型。事实上golang的
strings.Builder
是最接近C++的std::string
的,它的大小是32字节。