先上代码:
func TestSlice2(t *testing.T) {
e := []int32{1, 2, 3}
fmt.Println("cap of e before:", cap(e))
e = append(e, 4, 5, 6, 7)
fmt.Println("cap of e after:", cap(e))
}
关于上述代码的输出,如果按照网上大规模流传的说法会按以下规则进行扩容(基于Go 1.18):
新扩容容量>当前容量的2倍旧容量< 256旧容量≥ 256初始容量为 0源码如下:
// go 1.18 src/runtime/slice.go:178
func growslice(et *_type, old slice, cap int) slice {
// ……
newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
newcap = cap
} else {
const threshold = 256
if old.cap < threshold {
newcap = doublecap
} else {
for 0 < newcap && newcap < cap {
// Transition from growing 2x for small slices
// to growing 1.25x for large slices. This formula
// gives a smooth-ish transition between the two.
newcap += (newcap + 3*threshold) / 4
}
if newcap <= 0 {
newcap = cap
}
}
}
// ……
}
cap=== RUN TestSlice2
cap of e before: 3
cap of e after: 8
--- PASS: TestSlice2 (0.00s)
PASS
Process finished with the exit code 0容量实际上会是 8,这是为什么呢?
growsliceroundupsizenewcapcapmem = roundupsize(uintptr(newcap) * ptrSize)
newcap = int(capmem / ptrSize)
ptrSizenewcaproundupsize7 * 8 = 56roundupsizefunc roundupsize(size uintptr) uintptr {
if size < _MaxSmallSize {
if size <= smallSizeMax-8 {
return uintptr(class_to_size[size_to_class8[(size+smallSizeDiv-1)/smallSizeDiv]])
} else {
//……
}
}
//……
}
部分变量值:
const _MaxSmallSize = 32768
const smallSizeMax = 1024
const smallSizeDiv = 8
var size_to_class8 = [smallSizeMax/smallSizeDiv + 1]uint8{0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31}
var class_to_size = [_NumSizeClasses]uint16{0, 8, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 256, 288, 320, 352, 384, 416, 448, 480, 512, 576, 640, 704, 768, 896, 1024, 1152, 1280, 1408, 1536, 1792, 2048, 2304, 2688, 3072, 3200, 3456, 4096, 4864, 5376, 6144, 6528, 6784, 6912, 8192, 9472, 9728, 10240, 10880, 12288, 13568, 14336, 16384, 18432, 19072, 20480, 21760, 24576, 27264, 28672, 32768}
roundupsizeuintptr(class_to_size[size_to_class8[(size+smallSizeDiv-1)/smallSizeDiv]])(size+smallSizeDiv-1)/smallSizeDiv = (56 + 8 - 1) / 8 = 7size_to_class8[7] = 5class_to_size[5] = 64roundopsizenewcap = int(capmem / ptrSize) = int(64 / 8) = 8如果文章对您有所帮助,别忘了点赞收藏哦~