【问题标题】:Why does an empty slice have 24 bytes?为什么空切片有 24 个字节?
【发布时间】:2021-08-22 15:45:43
【问题描述】:

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

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

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

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

【问题讨论】:

标签: go optimization size slice sizeof


【解决方案1】:

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

如果您阅读documentation 中的unsafe.Sizeof,它会解释这里发生了什么:

大小不包括 x 可能引用的任何内存。例如,如果 x 是一个切片,Sizeof 返回切片描述符的大小,而不是切片引用的内存大小。

【讨论】:

  • 切片描述符的内存布局请参见SliceHeader
【解决方案2】:

unsafe.Sizeof内存中对象的大小,与 C 和 C++ 中的 sizeof 完全相同。见How to get memory size of variable?

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

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

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

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

【讨论】:

    猜你喜欢
    • 2022-07-06
    • 1970-01-01
    • 1970-01-01
    • 2018-08-15
    • 1970-01-01
    • 1970-01-01
    • 2023-02-25
    • 1970-01-01
    • 2016-08-29
    相关资源
    最近更新 更多