Go slice扩容机制?

Go 1.18版本之前

扩容会发生在slice append的时候,当slice的cap不足以容纳新元素,就会进行扩容,扩容规则如下

  • 如果新申请容量比两倍原有容量大,那么扩容后容量大小 为 新申请容量
  • 如果原有 slice 长度小于 1024, 那么每次就扩容为原来的 2 倍
  • 如果原 slice 长度大于等于 1024, 那么每次扩容就扩为原来的 1.25 倍
  1. func main() {
  2. slice1 := []int{1, 2, 3}
  3. for i := 0; i < 16; i++ {
  4. slice1 = append(slice1, 1)
  5. fmt.Printf("addr: %p, len: %v, cap: %v
  6. ", slice1, len(slice1), cap(slice1))
  7. }
  8. }
  1. addr: 0xc00001a120, len: 4, cap: 6
  2. addr: 0xc00001a120, len: 5, cap: 6
  3. addr: 0xc00001a120, len: 6, cap: 6
  4. addr: 0xc000060060, len: 7, cap: 12
  5. addr: 0xc000060060, len: 8, cap: 12
  6. addr: 0xc000060060, len: 9, cap: 12
  7. addr: 0xc000060060, len: 10, cap: 12
  8. addr: 0xc000060060, len: 11, cap: 12
  9. addr: 0xc000060060, len: 12, cap: 12
  10. addr: 0xc00007c000, len: 13, cap: 24
  11. addr: 0xc00007c000, len: 14, cap: 24
  12. addr: 0xc00007c000, len: 15, cap: 24
  13. addr: 0xc00007c000, len: 16, cap: 24
  14. addr: 0xc00007c000, len: 17, cap: 24
  15. addr: 0xc00007c000, len: 18, cap: 24
  16. addr: 0xc00007c000, len: 19, cap: 24

Go 1.18版本切片扩容

Go1.18不再以1024为临界点,而是设定了一个值为256的threshold,以256为临界点;超过256,不再是每次扩容1/4,而是每次增加(旧容量+3*256)/4;

  • 当新切片需要的容量cap大于两倍扩容的容量,则直接按照新切片需要的容量扩容;
  • 当原 slice 容量 < threshold 的时候,新 slice 容量变成原来的 2 倍;
  • 当原 slice 容量 > threshold,进入一个循环,每次容量增加(旧容量+3*threshold)/4。

公式如下:

519.Go slice扩容机制? - 图1