golang slice (切片) 扩容机制详解(1.18版本后)
slice源码定义:
type slice struct {
array unsafe.Pointer //指向底层数组的指针
len int //切片长度
cap int //切片容量
}
growslice()方法:用于 slice 的扩容
func growslice(et *_type, old slice, cap int) slice {
// ......
newcap := old.cap
doublecap := newcap + newcap //双倍扩容(原容量的两倍)
if cap > doublecap { //如果所需容量大于 两倍扩容,则直接扩容到所需容量
newcap = cap
} else {
const threshold = 256 //这里设置了一个 阈值 -- 256
if old.cap < threshold { //如果旧容量 小于 256,则两倍扩容
newcap = doublecap
} else {
// 检查 0 < newcap 以检测溢出并防止无限循环。
for 0 < newcap && newcap < cap { //如果新容量 > 0 并且 原容量 小于 所需容量
// 从小片的增长2x过渡到大片的增长1.25x。这个公式给出了两者之间的平滑过渡。(这里的系数会随着容量的大小发生变化,从2.0到无线接近1.25)
newcap += (newcap + 3*threshold) / 4
//当newcap计算溢出时,将newcap设置为请求的上限。
if newcap <= 0 { // 如果发生了溢出,将新容量设置为请求的容量大小
newcap = cap
}
}
}
}
具体情况如下:
-
如果请求容量 大于 两倍现有容量 ,则新容量 直接为请求容量
-
否则(请求容量 小于等于 两倍现有容量)
如果 现有容量 小于 256 ,则新容量是原来的两倍
否则:新容量 = 1.25 原容量 + 3/4 阈值 “这个公式给出了从1.25倍增长 过渡到2 倍增长,两者之间的平滑过渡。” 在此情况下,如果发生了溢出,将新容量设置为请求的容量大小
注意:目前仍然存在追加顺序的问题:当前切片的扩容,严格依赖第一个切片的容量,以第一个切片的容量进行计算,如果交换两个切片,两种方式得到的新切片的容量大概率是不一样的
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步