前言
起因是一篇文章提到 Go 的切片扩容策略是“容量小于 1024 时,容量翻倍;容量大于等于 1024 时,容量增加 25%”。而我本地测试后与作者得出结论不同,故而上网搜寻资料。
正文
- 我尝试输出当切片长度从0增加到2000时,切片的容量变化情况,代码如下:
|
|
- 运行结果如下:
|
|
这显然不符合我在文章中看到的策略,找到一篇文章,其中提到 1.18 版本后策略如下:
当原slice容量(oldcap)小于256的时候,新slice(newcap)容量为原来的2倍;
原slice容量超过256,新slice容量 $newcap = oldcap+(oldcap+3*256)/4$。
原slice容量超过256,新slice容量 $newcap = oldcap+(oldcap+3*256)/4$。
这才对上了。
关于这个策略的实现,在 src/runtime/slice.go 的 growslice
函数,目前源码中的乘除运算已经被替换成了位运算,所以看起来比较复杂。
结语
在查找资料的过程中发现,哪怕是 1.18 以前的版本,在容量超过 1024 后,也不是严格按照 25% 增长,因为计算出 newcap 后,作了一个内存对齐,这和内存分配策略相关。最后的容量会大于等于基于前面计算得出的 newcap.
切片扩容的策略优化后,$newcap=oldcap+(oldcap+3*256)/4$, 通过添加一个常量让底层数组大小的增长更加平滑。