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

Why does an empty slice have 24 bytes?

我想了解使用 make([]int, 0) 创建空切片时会发生什么。我执行此代码进行测试:

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

大小和容量return很明显,都是0,但是slice的大小是24字节,为什么?

24 字节应该是 3 int64 对吧?一个 24 字节的切片的内部数组应该是这样的:[3]int{},那么为什么一个空切片有 24 个字节?

Go 中的所有数据类型都是静态大小的。由于切片的动态特性,元素的数量与类型没有任何关联。

如果您阅读 unsafe.Sizeofdocumentation,它会解释这里发生的事情:

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.

unsafe.Sizeof是对象在内存中的大小,和C、C++中的sizeof完全一样。参见 How to get memory size of variable?

切片有大小,但也有调整大小的能力,所以最大调整大小的能力也必须存储在某处。但是可调整大小也意味着它不能是静态数组,而是需要存储指向其他(可能是动态分配的)数组的指针

整个事情意味着它需要存储它的 { begin, end, last valid index } or {开始,大小,容量}。这是一个包含 3 个值的元组,这意味着它在 64 位平台上的内存表示至少为 3×8 字节,除非您想将最大大小和容量限制为远小于 264字节

在许多具有相同动态大小调整功能的 C++ 类型中情况完全相同,例如 std::stringstd::vector 也是 24 字节类型,尽管在某些实现中添加了 8 字节的填充对齐的原因,导致了一个 32 字节的字符串类型。参见

  • Why is sizeof(string) == 32?

事实上,golang 的 strings.Builder 最接近 C++ 的 std::string,其大小为 32 字节。参见 demo