在学习Go语言数组的append()函数时遇到一个有趣的现象,当我使用如下代码测试扩容的时候:
import "fmt"
func main() {
var numbers []int
printSlice(numbers)
numbers = append(numbers, 0)
printSlice(numbers)
numbers = append(numbers, 1)
printSlice(numbers)
numbers = append(numbers, 2)
printSlice(numbers)
numbers = append(numbers, 3)
printSlice(numbers)
numbers = append(numbers, 4)
printSlice(numbers)
numbers = append(numbers, 5, 6, 7)
printSlice(numbers)
numbers = append(numbers, 8)
printSlice(numbers)
numbers = append(numbers, 9, 10, 11)
printSlice(numbers)
}
func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
输出如下:
可以看到容量是以2倍的速率增长的,但是换一种测试方式:
package main
import "fmt"
func main() {
var numbers []int
printSlice(numbers)
numbers = append(numbers, 0)
printSlice(numbers)
numbers = append(numbers, 1, 2, 3, 4)
printSlice(numbers)
numbers = append(numbers, 5)
printSlice(numbers)
numbers = append(numbers, 6)
printSlice(numbers)
}
func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
输入如下:
结局似乎和预想的不太一样,第一次添加一个元素,扩容到了长度和容量都为1的情况,第二次一次性添加了四个元素,当按照二倍增长来推算的话首先cap要增长到2,发现不够后继续增长2倍到4,发现还是不够,继续增长到8,所以当我一次性添加四个元素的时候,本应该输出len=5 cap=8 slice=[0 1 2 3 4],但实际输出的cap是6,由此可知:
在Go语言中,通过append()函数向slice中添加元素,按照二倍增长后capacity依然不够用时,会将capacity设置为当前数组的length+1.
更正!!!
更新了实验,我有点摸不透了兄弟们...(向初始cap为0的空slice中一次性添加1个、2个、...、300个的实验代码和结果如下,大概看了一下扩容后cap的计算结果,还是有些规律的,不过具体的算法懒得梳理了,有感兴趣的大佬可以告知一下)
package main
import "fmt"
func printSliceBefore(x []int) {
fmt.Printf("init len[%d] cap[%d] -> ", len(x), cap(x))
}
func printSliceAfter(x []int) {
fmt.Printf("After append: len[%d] cap[%d]\n", len(x), cap(x))
}
func main() {
for i := 1; i <= 300; i++ {
var numbers = make([]int, 0)
printSliceBefore(numbers)
numbers = append(numbers, make([]int, i)...)
printSliceAfter(numbers)
}
}
=======================================================
[Running] go run "c:\Users\Hyleon\hello\hello.go"
init len[0] cap[0] -> After append: len[1] cap[1]
init len[0] cap[0] -> After append: len[2] cap[2]
init len[0] cap[0] -> After append: len[3] cap[3]
init len[0] cap[0] -> After append: len[4] cap[4]
init len[0] cap[0] -> After append: len[5] cap[6]
init len[0] cap[0] -> After append: len[6] cap[6]
init len[0] cap[0] -> After append: len[7] cap[8]
init len[0] cap[0] -> After append: len[8] cap[8]
init len[0] cap[0] -> After append: len[9] cap[10]
init len[0] cap[0] -> After append: len[10] cap[10]
init len[0] cap[0] -> After append: len[11] cap[12]
init len[0] cap[0] -> After append: len[12] cap[12]
init len[0] cap[0] -> After append: len[13] cap[14]
init len[0] cap[0] -> After append: len[14] cap[14]
init len[0] cap[0] -> After append: len[15] cap[16]
init len[0] cap[0] -> After append: len[16] cap[16]
init len[0] cap[0] -> After append: len[17] cap[18]
init len[0] cap[0] -> After append: len[18] cap[18]
init len[0] cap[0] -> After append: len[19] cap[20]
init len[0] cap[0] -> After append: len[20] cap[20]
init len[0] cap[0] -> After append: len[21] cap[22]
init len[0] cap[0] -> After append: len[22] cap[22]
init len[0] cap[0] -> After append: len[23] cap[24]
init len[0] cap[0] -> After append: len[24] cap[24]
init len[0] cap[0] -> After append: len[25] cap[26]
init len[0] cap[0] -> After append: len[26] cap[26]
init len[0] cap[0] -> After append: len[27] cap[28]
init len[0] cap[0] -> After append: len[28] cap[28]
init len[0] cap[0] -> After append: len[29] cap[30]
init len[0] cap[0] -> After append: len[30] cap[30]
init len[0] cap[0] -> After append: len[31] cap[32]
init len[0] cap[0] -> After append: len[32] cap[32]
init len[0] cap[0] -> After append: len[33] cap[36]
init len[0] cap[0] -> After append: len[34] cap[36]
init len[0] cap[0] -> After append: len[35] cap[36]
init len[0] cap[0] -> After append: len[36] cap[36]
init len[0] cap[0] -> After append: len[37] cap[40]
init len[0] cap[0] -> After append: len[38] cap[40]
init len[0] cap[0] -> After append: len[39] cap[40]
init len[0] cap[0] -> After append: len[40] cap[40]
init len[0] cap[0] -> After append: len[41] cap[44]
init len[0] cap[0] -> After append: len[42] cap[44]
init len[0] cap[0] -> After append: len[43] cap[44]
init len[0] cap[0] -> After append: len[44] cap[44]
init len[0] cap[0] -> After append: len[45] cap[48]
init len[0] cap[0] -> After append: len[46] cap[48]
init len[0] cap[0] -> After append: len[47] cap[48]
init len[0] cap[0] -> After append: len[48] cap[48]
init len[0] cap[0] -> After append: len[49] cap[52]
init len[0] cap[0] -> After append: len[50] cap[52]
init len[0] cap[0] -> After append: len[51] cap[52]
init len[0] cap[0] -> After append: len[52] cap[52]
init len[0] cap[0] -> After append: len[53] cap[56]
init len[0] cap[0] -> After append: len[54] cap[56]
init len[0] cap[0] -> After append: len[55] cap[56]
init len[0] cap[0] -> After append: len[56] cap[56]
init len[0] cap[0] -> After append: len[57] cap[60]
init len[0] cap[0] -> After append: len[58] cap[60]
init len[0] cap[0] -> After append: len[59] cap[60]
init len[0] cap[0] -> After append: len[60] cap[60]
init len[0] cap[0] -> After append: len[61] cap[64]
init len[0] cap[0] -> After append: len[62] cap[64]
init len[0] cap[0] -> After append: len[63] cap[64]
init len[0] cap[0] -> After append: len[64] cap[64]
init len[0] cap[0] -> After append: len[65] cap[72]
init len[0] cap[0] -> After append: len[66] cap[72]
init len[0] cap[0] -> After append: len[67] cap[72]
init len[0] cap[0] -> After append: len[68] cap[72]
init len[0] cap[0] -> After append: len[69] cap[72]
init len[0] cap[0] -> After append: len[70] cap[72]
init len[0] cap[0] -> After append: len[71] cap[72]
init len[0] cap[0] -> After append: len[72] cap[72]
init len[0] cap[0] -> After append: len[73] cap[80]
init len[0] cap[0] -> After append: len[74] cap[80]
init len[0] cap[0] -> After append: len[75] cap[80]
init len[0] cap[0] -> After append: len[76] cap[80]
init len[0] cap[0] -> After append: len[77] cap[80]
init len[0] cap[0] -> After append: len[78] cap[80]
init len[0] cap[0] -> After append: len[79] cap[80]
init len[0] cap[0] -> After append: len[80] cap[80]
init len[0] cap[0] -> After append: len[81] cap[88]
init len[0] cap[0] -> After append: len[82] cap[88]
init len[0] cap[0] -> After append: len[83] cap[88]
init len[0] cap[0] -> After append: len[84] cap[88]
init len[0] cap[0] -> After append: len[85] cap[88]
init len[0] cap[0] -> After append: len[86] cap[88]
init len[0] cap[0] -> After append: len[87] cap[88]
init len[0] cap[0] -> After append: len[88] cap[88]
init len[0] cap[0] -> After append: len[89] cap[96]
init len[0] cap[0] -> After append: len[90] cap[96]
init len[0] cap[0] -> After append: len[91] cap[96]
init len[0] cap[0] -> After append: len[92] cap[96]
init len[0] cap[0] -> After append: len[93] cap[96]
init len[0] cap[0] -> After append: len[94] cap[96]
init len[0] cap[0] -> After append: len[95] cap[96]
init len[0] cap[0] -> After append: len[96] cap[96]
init len[0] cap[0] -> After append: len[97] cap[112]
init len[0] cap[0] -> After append: len[98] cap[112]
init len[0] cap[0] -> After append: len[99] cap[112]
init len[0] cap[0] -> After append: len[100] cap[112]
init len[0] cap[0] -> After append: len[101] cap[112]
init len[0] cap[0] -> After append: len[102] cap[112]
init len[0] cap[0] -> After append: len[103] cap[112]
init len[0] cap[0] -> After append: len[104] cap[112]
init len[0] cap[0] -> After append: len[105] cap[112]
init len[0] cap[0] -> After append: len[106] cap[112]
init len[0] cap[0] -> After append: len[107] cap[112]
init len[0] cap[0] -> After append: len[108] cap[112]
init len[0] cap[0] -> After append: len[109] cap[112]
init len[0] cap[0] -> After append: len[110] cap[112]
init len[0] cap[0] -> After append: len[111] cap[112]
init len[0] cap[0] -> After append: len[112] cap[112]
init len[0] cap[0] -> After append: len[113] cap[128]
init len[0] cap[0] -> After append: len[114] cap[128]
init len[0] cap[0] -> After append: len[115] cap[128]
init len[0] cap[0] -> After append: len[116] cap[128]
init len[0] cap[0] -> After append: len[117] cap[128]
init len[0] cap[0] -> After append: len[118] cap[128]
init len[0] cap[0] -> After append: len[119] cap[128]
init len[0] cap[0] -> After append: len[120] cap[128]
init len[0] cap[0] -> After append: len[121] cap[128]
init len[0] cap[0] -> After append: len[122] cap[128]
init len[0] cap[0] -> After append: len[123] cap[128]
init len[0] cap[0] -> After append: len[124] cap[128]
init len[0] cap[0] -> After append: len[125] cap[128]
init len[0] cap[0] -> After append: len[126] cap[128]
init len[0] cap[0] -> After append: len[127] cap[128]
init len[0] cap[0] -> After append: len[128] cap[128]
init len[0] cap[0] -> After append: len[129] cap[144]
init len[0] cap[0] -> After append: len[130] cap[144]
init len[0] cap[0] -> After append: len[131] cap[144]
init len[0] cap[0] -> After append: len[132] cap[144]
init len[0] cap[0] -> After append: len[133] cap[144]
init len[0] cap[0] -> After append: len[134] cap[144]
init len[0] cap[0] -> After append: len[135] cap[144]
init len[0] cap[0] -> After append: len[136] cap[144]
init len[0] cap[0] -> After append: len[137] cap[144]
init len[0] cap[0] -> After append: len[138] cap[144]
init len[0] cap[0] -> After append: len[139] cap[144]
init len[0] cap[0] -> After append: len[140] cap[144]
init len[0] cap[0] -> After append: len[141] cap[144]
init len[0] cap[0] -> After append: len[142] cap[144]
init len[0] cap[0] -> After append: len[143] cap[144]
init len[0] cap[0] -> After append: len[144] cap[144]
init len[0] cap[0] -> After append: len[145] cap[160]
init len[0] cap[0] -> After append: len[146] cap[160]
init len[0] cap[0] -> After append: len[147] cap[160]
init len[0] cap[0] -> After append: len[148] cap[160]
init len[0] cap[0] -> After append: len[149] cap[160]
init len[0] cap[0] -> After append: len[150] cap[160]
init len[0] cap[0] -> After append: len[151] cap[160]
init len[0] cap[0] -> After append: len[152] cap[160]
init len[0] cap[0] -> After append: len[153] cap[160]
init len[0] cap[0] -> After append: len[154] cap[160]
init len[0] cap[0] -> After append: len[155] cap[160]
init len[0] cap[0] -> After append: len[156] cap[160]
init len[0] cap[0] -> After append: len[157] cap[160]
init len[0] cap[0] -> After append: len[158] cap[160]
init len[0] cap[0] -> After append: len[159] cap[160]
init len[0] cap[0] -> After append: len[160] cap[160]
init len[0] cap[0] -> After append: len[161] cap[176]
init len[0] cap[0] -> After append: len[162] cap[176]
init len[0] cap[0] -> After append: len[163] cap[176]
init len[0] cap[0] -> After append: len[164] cap[176]
init len[0] cap[0] -> After append: len[165] cap[176]
init len[0] cap[0] -> After append: len[166] cap[176]
init len[0] cap[0] -> After append: len[167] cap[176]
init len[0] cap[0] -> After append: len[168] cap[176]
init len[0] cap[0] -> After append: len[169] cap[176]
init len[0] cap[0] -> After append: len[170] cap[176]
init len[0] cap[0] -> After append: len[171] cap[176]
init len[0] cap[0] -> After append: len[172] cap[176]
init len[0] cap[0] -> After append: len[173] cap[176]
init len[0] cap[0] -> After append: len[174] cap[176]
init len[0] cap[0] -> After append: len[175] cap[176]
init len[0] cap[0] -> After append: len[176] cap[176]
init len[0] cap[0] -> After append: len[177] cap[192]
init len[0] cap[0] -> After append: len[178] cap[192]
init len[0] cap[0] -> After append: len[179] cap[192]
init len[0] cap[0] -> After append: len[180] cap[192]
init len[0] cap[0] -> After append: len[181] cap[192]
init len[0] cap[0] -> After append: len[182] cap[192]
init len[0] cap[0] -> After append: len[183] cap[192]
init len[0] cap[0] -> After append: len[184] cap[192]
init len[0] cap[0] -> After append: len[185] cap[192]
init len[0] cap[0] -> After append: len[186] cap[192]
init len[0] cap[0] -> After append: len[187] cap[192]
init len[0] cap[0] -> After append: len[188] cap[192]
init len[0] cap[0] -> After append: len[189] cap[192]
init len[0] cap[0] -> After append: len[190] cap[192]
init len[0] cap[0] -> After append: len[191] cap[192]
init len[0] cap[0] -> After append: len[192] cap[192]
init len[0] cap[0] -> After append: len[193] cap[224]
init len[0] cap[0] -> After append: len[194] cap[224]
init len[0] cap[0] -> After append: len[195] cap[224]
init len[0] cap[0] -> After append: len[196] cap[224]
init len[0] cap[0] -> After append: len[197] cap[224]
init len[0] cap[0] -> After append: len[198] cap[224]
init len[0] cap[0] -> After append: len[199] cap[224]
init len[0] cap[0] -> After append: len[200] cap[224]
init len[0] cap[0] -> After append: len[201] cap[224]
init len[0] cap[0] -> After append: len[202] cap[224]
init len[0] cap[0] -> After append: len[203] cap[224]
init len[0] cap[0] -> After append: len[204] cap[224]
init len[0] cap[0] -> After append: len[205] cap[224]
init len[0] cap[0] -> After append: len[206] cap[224]
init len[0] cap[0] -> After append: len[207] cap[224]
init len[0] cap[0] -> After append: len[208] cap[224]
init len[0] cap[0] -> After append: len[209] cap[224]
init len[0] cap[0] -> After append: len[210] cap[224]
init len[0] cap[0] -> After append: len[211] cap[224]
init len[0] cap[0] -> After append: len[212] cap[224]
init len[0] cap[0] -> After append: len[213] cap[224]
init len[0] cap[0] -> After append: len[214] cap[224]
init len[0] cap[0] -> After append: len[215] cap[224]
init len[0] cap[0] -> After append: len[216] cap[224]
init len[0] cap[0] -> After append: len[217] cap[224]
init len[0] cap[0] -> After append: len[218] cap[224]
init len[0] cap[0] -> After append: len[219] cap[224]
init len[0] cap[0] -> After append: len[220] cap[224]
init len[0] cap[0] -> After append: len[221] cap[224]
init len[0] cap[0] -> After append: len[222] cap[224]
init len[0] cap[0] -> After append: len[223] cap[224]
init len[0] cap[0] -> After append: len[224] cap[224]
init len[0] cap[0] -> After append: len[225] cap[256]
init len[0] cap[0] -> After append: len[226] cap[256]
init len[0] cap[0] -> After append: len[227] cap[256]
init len[0] cap[0] -> After append: len[228] cap[256]
init len[0] cap[0] -> After append: len[229] cap[256]
init len[0] cap[0] -> After append: len[230] cap[256]
init len[0] cap[0] -> After append: len[231] cap[256]
init len[0] cap[0] -> After append: len[232] cap[256]
init len[0] cap[0] -> After append: len[233] cap[256]
init len[0] cap[0] -> After append: len[234] cap[256]
init len[0] cap[0] -> After append: len[235] cap[256]
init len[0] cap[0] -> After append: len[236] cap[256]
init len[0] cap[0] -> After append: len[237] cap[256]
init len[0] cap[0] -> After append: len[238] cap[256]
init len[0] cap[0] -> After append: len[239] cap[256]
init len[0] cap[0] -> After append: len[240] cap[256]
init len[0] cap[0] -> After append: len[241] cap[256]
init len[0] cap[0] -> After append: len[242] cap[256]
init len[0] cap[0] -> After append: len[243] cap[256]
init len[0] cap[0] -> After append: len[244] cap[256]
init len[0] cap[0] -> After append: len[245] cap[256]
init len[0] cap[0] -> After append: len[246] cap[256]
init len[0] cap[0] -> After append: len[247] cap[256]
init len[0] cap[0] -> After append: len[248] cap[256]
init len[0] cap[0] -> After append: len[249] cap[256]
init len[0] cap[0] -> After append: len[250] cap[256]
init len[0] cap[0] -> After append: len[251] cap[256]
init len[0] cap[0] -> After append: len[252] cap[256]
init len[0] cap[0] -> After append: len[253] cap[256]
init len[0] cap[0] -> After append: len[254] cap[256]
init len[0] cap[0] -> After append: len[255] cap[256]
init len[0] cap[0] -> After append: len[256] cap[256]
init len[0] cap[0] -> After append: len[257] cap[288]
init len[0] cap[0] -> After append: len[258] cap[288]
init len[0] cap[0] -> After append: len[259] cap[288]
init len[0] cap[0] -> After append: len[260] cap[288]
init len[0] cap[0] -> After append: len[261] cap[288]
init len[0] cap[0] -> After append: len[262] cap[288]
init len[0] cap[0] -> After append: len[263] cap[288]
init len[0] cap[0] -> After append: len[264] cap[288]
init len[0] cap[0] -> After append: len[265] cap[288]
init len[0] cap[0] -> After append: len[266] cap[288]
init len[0] cap[0] -> After append: len[267] cap[288]
init len[0] cap[0] -> After append: len[268] cap[288]
init len[0] cap[0] -> After append: len[269] cap[288]
init len[0] cap[0] -> After append: len[270] cap[288]
init len[0] cap[0] -> After append: len[271] cap[288]
init len[0] cap[0] -> After append: len[272] cap[288]
init len[0] cap[0] -> After append: len[273] cap[288]
init len[0] cap[0] -> After append: len[274] cap[288]
init len[0] cap[0] -> After append: len[275] cap[288]
init len[0] cap[0] -> After append: len[276] cap[288]
init len[0] cap[0] -> After append: len[277] cap[288]
init len[0] cap[0] -> After append: len[278] cap[288]
init len[0] cap[0] -> After append: len[279] cap[288]
init len[0] cap[0] -> After append: len[280] cap[288]
init len[0] cap[0] -> After append: len[281] cap[288]
init len[0] cap[0] -> After append: len[282] cap[288]
init len[0] cap[0] -> After append: len[283] cap[288]
init len[0] cap[0] -> After append: len[284] cap[288]
init len[0] cap[0] -> After append: len[285] cap[288]
init len[0] cap[0] -> After append: len[286] cap[288]
init len[0] cap[0] -> After append: len[287] cap[288]
init len[0] cap[0] -> After append: len[288] cap[288]
init len[0] cap[0] -> After append: len[289] cap[336]
init len[0] cap[0] -> After append: len[290] cap[336]
init len[0] cap[0] -> After append: len[291] cap[336]
init len[0] cap[0] -> After append: len[292] cap[336]
init len[0] cap[0] -> After append: len[293] cap[336]
init len[0] cap[0] -> After append: len[294] cap[336]
init len[0] cap[0] -> After append: len[295] cap[336]
init len[0] cap[0] -> After append: len[296] cap[336]
init len[0] cap[0] -> After append: len[297] cap[336]
init len[0] cap[0] -> After append: len[298] cap[336]
init len[0] cap[0] -> After append: len[299] cap[336]
init len[0] cap[0] -> After append: len[300] cap[336]
[Done] exited with code=0 in 0.655 seconds
如果设定初始cap为10,实验结果在开始时略微不同,后面的变化规律与前面的实验一致,所以仅设置循环40次
package main
import "fmt"
func printSliceBefore(x []int) {
fmt.Printf("init len[%d] cap[%d] -> ", len(x), cap(x))
}
func printSliceAfter(x []int) {
fmt.Printf("After append: len[%d] cap[%d]\n", len(x), cap(x))
}
func main() {
for i := 1; i <= 40; i++ {
var numbers = make([]int, 0, 10)
printSliceBefore(numbers)
numbers = append(numbers, make([]int, i)...)
printSliceAfter(numbers)
}
}
==========================================================
[Running] go run "c:\Users\Hyleon\hello\hello.go"
init len[0] cap[10] -> After append: len[1] cap[10]
init len[0] cap[10] -> After append: len[2] cap[10]
init len[0] cap[10] -> After append: len[3] cap[10]
init len[0] cap[10] -> After append: len[4] cap[10]
init len[0] cap[10] -> After append: len[5] cap[10]
init len[0] cap[10] -> After append: len[6] cap[10]
init len[0] cap[10] -> After append: len[7] cap[10]
init len[0] cap[10] -> After append: len[8] cap[10]
init len[0] cap[10] -> After append: len[9] cap[10]
init len[0] cap[10] -> After append: len[10] cap[10]
init len[0] cap[10] -> After append: len[11] cap[20]
init len[0] cap[10] -> After append: len[12] cap[20]
init len[0] cap[10] -> After append: len[13] cap[20]
init len[0] cap[10] -> After append: len[14] cap[20]
init len[0] cap[10] -> After append: len[15] cap[20]
init len[0] cap[10] -> After append: len[16] cap[20]
init len[0] cap[10] -> After append: len[17] cap[20]
init len[0] cap[10] -> After append: len[18] cap[20]
init len[0] cap[10] -> After append: len[19] cap[20]
init len[0] cap[10] -> After append: len[20] cap[20]
init len[0] cap[10] -> After append: len[21] cap[22]
init len[0] cap[10] -> After append: len[22] cap[22]
init len[0] cap[10] -> After append: len[23] cap[24]
init len[0] cap[10] -> After append: len[24] cap[24]
init len[0] cap[10] -> After append: len[25] cap[26]
init len[0] cap[10] -> After append: len[26] cap[26]
init len[0] cap[10] -> After append: len[27] cap[28]
init len[0] cap[10] -> After append: len[28] cap[28]
init len[0] cap[10] -> After append: len[29] cap[30]
init len[0] cap[10] -> After append: len[30] cap[30]
init len[0] cap[10] -> After append: len[31] cap[32]
init len[0] cap[10] -> After append: len[32] cap[32]
init len[0] cap[10] -> After append: len[33] cap[36]
init len[0] cap[10] -> After append: len[34] cap[36]
init len[0] cap[10] -> After append: len[35] cap[36]
init len[0] cap[10] -> After append: len[36] cap[36]
init len[0] cap[10] -> After append: len[37] cap[40]
init len[0] cap[10] -> After append: len[38] cap[40]
init len[0] cap[10] -> After append: len[39] cap[40]
init len[0] cap[10] -> After append: len[40] cap[40]
[Done] exited with code=0 in 0.644 seconds
扩容算法代码如下:
// growslice handles slice growth during append.
// It is passed the slice element type, the old slice, and the desired new minimum capacity,
// and it returns a new slice with at least that capacity, with the old data
// copied into it.
// The new slice's length is set to the old slice's length,
// NOT to the new requested capacity.
// This is for codegen convenience. The old slice's length is used immediately
// to calculate where to write new values during an append.
// TODO: When the old backend is gone, reconsider this decision.
// The SSA backend might prefer the new length or to return only ptr/cap and save stack space.
func growslice(et *_type, old slice, cap int) slice {
if raceenabled {
callerpc := getcallerpc()
racereadrangepc(old.array, uintptr(old.len*int(et.size)), callerpc, funcPC(growslice))
}
if msanenabled {
msanread(old.array, uintptr(old.len*int(et.size)))
}
if cap < old.cap {
panic(errorString("growslice: cap out of range"))
}
if et.size == 0 {
// append should not create a slice with nil pointer but non-zero len.
// We assume that append doesn't need to preserve old.array in this case.
return slice{unsafe.Pointer(&zerobase), old.len, cap}
}
newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
newcap = cap
} else {
if old.cap < 1024 {
newcap = doublecap
} else {
// Check 0 < newcap to detect overflow
// and prevent an infinite loop.
for 0 < newcap && newcap < cap {
newcap += newcap / 4
}
// Set newcap to the requested cap when
// the newcap calculation overflowed.
if newcap <= 0 {
newcap = cap
}
}
}
var overflow bool
var lenmem, newlenmem, capmem uintptr
// Specialize for common values of et.size.
// For 1 we don't need any division/multiplication.
// For sys.PtrSize, compiler will optimize division/multiplication into a shift by a constant.
// For powers of 2, use a variable shift.
switch {
case et.size == 1:
lenmem = uintptr(old.len)
newlenmem = uintptr(cap)
capmem = roundupsize(uintptr(newcap))
overflow = uintptr(newcap) > maxAlloc
newcap = int(capmem)
case et.size == sys.PtrSize:
lenmem = uintptr(old.len) * sys.PtrSize
newlenmem = uintptr(cap) * sys.PtrSize
capmem = roundupsize(uintptr(newcap) * sys.PtrSize)
overflow = uintptr(newcap) > maxAlloc/sys.PtrSize
newcap = int(capmem / sys.PtrSize)
case isPowerOfTwo(et.size):
var shift uintptr
if sys.PtrSize == 8 {
// Mask shift for better code generation.
shift = uintptr(sys.Ctz64(uint64(et.size))) & 63
} else {
shift = uintptr(sys.Ctz32(uint32(et.size))) & 31
}
lenmem = uintptr(old.len) << shift
newlenmem = uintptr(cap) << shift
capmem = roundupsize(uintptr(newcap) << shift)
overflow = uintptr(newcap) > (maxAlloc >> shift)
newcap = int(capmem >> shift)
default:
lenmem = uintptr(old.len) * et.size
newlenmem = uintptr(cap) * et.size
capmem, overflow = math.MulUintptr(et.size, uintptr(newcap))
capmem = roundupsize(capmem)
newcap = int(capmem / et.size)
}
// The check of overflow in addition to capmem > maxAlloc is needed
// to prevent an overflow which can be used to trigger a segfault
// on 32bit architectures with this example program:
//
// type T [1<<27 + 1]int64
//
// var d T
// var s []T
//
// func main() {
// s = append(s, d, d, d, d)
// print(len(s), "\n")
// }
if overflow || capmem > maxAlloc {
panic(errorString("growslice: cap out of range"))
}
var p unsafe.Pointer
if et.ptrdata == 0 {
p = mallocgc(capmem, nil, false)
// The append() that calls growslice is going to overwrite from old.len to cap (which will be the new length).
// Only clear the part that will not be overwritten.
memclrNoHeapPointers(add(p, newlenmem), capmem-newlenmem)
} else {
// Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory.
p = mallocgc(capmem, et, true)
if lenmem > 0 && writeBarrier.enabled {
// Only shade the pointers in old.array since we know the destination slice p
// only contains nil pointers because it has been cleared during alloc.
bulkBarrierPreWriteSrcOnly(uintptr(p), uintptr(old.array), lenmem-et.size+et.ptrdata)
}
}
memmove(p, old.array, lenmem)
return slice{p, old.len, newcap}
}