G

[Go] 1.18版本后的Slice扩容

RoLingG Golang 2025-10-19

1.18版本后的Slice扩容

新版公式: newcap += (newcap + 3*threshold) / 4threshold 默认为256

1.18 之前(老算法)

  • 无论容量多大,一律 按 2 倍 往上翻。
    结果:

    • 小切片(<128 B)没问题,几次就够用;
    • 大切片(>1 MB)也 2 倍涨,第一次 1M→2M,第二次 2M→4M……
      内存浪费明显,而且越往后每次浪费越夸张。

1.18 之后(新算法)

目标:小切片涨得快,大切片涨得慢,减少内存浪费。
于是引入一个 threshold = 256 的“阈值”,把扩容策略拆成三段:

  1. 期望容量 > 2×旧容量
    用户一次性 append 很多,直接“一步到位”用期望容量,避免多次扩容。
  2. 旧容量 < 256(小切片)(256 是元素个数)
    仍然保持 2 倍,让小切片快速长大,减少扩容次数。
  3. 旧容量 ≥ 256(大切片)
    不再 2 倍,而是改为 “平滑因子”增长,核心代码就是:

    newcap += (newcap + 3*threshold) / 4

    把 threshold=256 代入:

    newcap += (newcap + 768) / 4

    等价于

    newcap = newcap * 1.25 + 192   // 近似 1.25 倍

    也就是说:

    • 增长系数从 2.0 降到 约 1.25
    • 随着 newcap 越来越大,常数项 192 占比越来越小,实际系数趋近于 1.25
      这样 1 MB 的切片下一次只涨到 1.25 MB 左右,而不是 2 MB,内存压力大幅缓解。

总结

那行代码newcap += (newcap + 3*threshold) / 4
就是 Go1.18 给“大切片”设计的 1.25 倍缓慢增长公式
用“加法式”而不是“乘法”实现,既避免浮点,又让涨幅从 2 倍平滑降到 1.25 倍左右,兼顾 CPU 和内存效率。

PREV
[kafka] 实操记录

评论(0)

发布评论