为什么Go切片在使用append时,初始容量会随着int32和int64类型的不同而变化?

问题描述 投票:0回答:1

我注意到在 Go 中将元素附加到不同整数类型(

int32
int64
)的切片时出现意外行为。具体来说,尽管附加了相同数量的元素,但分配给这些切片的初始容量似乎根据类型而有所不同。

例如,当我初始化一个切片并使用可变参数附加函数附加一个元素时,容量会有所不同:

s1 := []int64{}
s2 := []int32{}
s1 = append(s1, []int64{0}...) // len:1, cap:1
s2 = append(s2, []int32{0}...) // len:1, cap:2

同样,当附加三个元素时:

s1 = append(s1, []int64{1, 2, 3}...) // len:3, cap:3
s2 = append(s2, []int32{1, 2, 3}...) // len:3, cap:4

但是,当我增量追加元素时,两个切片都表现出相同的增长模式:

s1 := []int64{}
s2 := []int32{}
s1 = append(s1, 1) // len:1, cap:1
s1 = append(s1, 2) // len:2, cap:2
s1 = append(s1, 3) // len:3 cap:4

s2 = append(s2, 1) // len:1, cap:2
s2 = append(s2, 2) // len:2, cap:2
s2 = append(s2, 3) // len:3 cap:4

有人可以解释为什么 Go 的追加函数在元素成组追加时为不同类型的切片分配不同的容量(

int32
int64
),而不是一次追加一个元素时吗?此行为是否记录在某处,或者是运行时的实现细节?

go memory-management slice
1个回答
0
投票

正如评论中提到的,这将与内存对齐和您正在使用的架构的字大小有关。

在 64 位平台上,CPU 寄存器的大小为 64 位(或 8 字节)。标准

int
类型将是 64 位,指针也是如此,并且 64 位浮点数可能也将是最常用的。

大量数据以 8 字节块的形式移动,因此架构的各个方面都可以针对 8 字节内存块进行优化。您应该看到类似的模式,其中

int8
切片从
0
跳转到
8
容量,以及
int16
切片从
0
跳转到
4

值得考虑的是,底层数组数据是堆分配的,如果我们为不断增长的

[]int32
分配4字节内存,那么有一个4字节空间对于那些8字节整数、指针、并且浮动,因此当我们将更多的空间转储到堆上时,堆管理器将在分配空间时留下该间隙。这些额外的 4 个字节在最好的情况下也不太可能特别有用,在最坏的情况下会导致堆碎片。

© www.soinside.com 2019 - 2024. All rights reserved.