go slice扩容需要经过下面两个步骤。
1.预估扩容后容量
go slice扩容例子
ints := []int{1, 2} ----> 扩容前容量 oldCap = 2
ints = append(ints, 3, 4, 5) ----> 至少扩容到 cap = 5
了解一下预估规则
- 在原容量扩大两倍还要小于扩容后的容量时,预估容量就是扩容后的
- 当大于扩容后的时,如果小于1024时,预估容量是扩容前容量的2倍
- 当大于扩容后的时,如果大于1024时,预估容量是扩容前容量的1.25倍,即以0.25增加
2.计算需要多大内存
所需内存 = 预估容量 * 元素类型大小
这里以int 举例,int在64位操作上默认是int64,即8个字节,所以元素类型不一样,内存也不一样,内存这里需要了解golang的内存管理模块,源码在runtime/sizeclasses.go
// class bytes/obj bytes/span objects tail waste max waste
// 1 8 8192 1024 0 87.50%
// 2 16 8192 512 0 43.75%
// 3 32 8192 256 0 46.88%
// 4 48 8192 170 32 31.52%
...
// 17 256 8192 32 0 5.86%
// 18 288 8192 28 128 12.16%
// 19 320 8192 25 192 11.80%
// 20 352 8192 23 96 9.88%
// 21 384 8192 21 128 9.51%
// 22 416 8192 19 288 10.71%
// 23 448 8192 18 128 8.37%
// 24 480 8192 17 32 6.82%
// 25 512 8192 16 0 6.05%
...
// 66 32768 32768 1 0 12.50%
通过阅读源码可以知道,在小于16字节时,每次以8个字节增加,当大于16小于2^8时,每次以16字节增加,当大于2^8小于2^9时以32字节增加,依此规律…
申请内存时,选择相近的,且大于等于需要的大小
接着之前的例子,扩容大小计算如下:
- 在之前的例子中,预估容量为5
- 1个int是8个字节,5 * 8 = 40
- 最合适的内存规格是48,所以48 / 8 = 6
- 所以内存会扩容到 6 个容量