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
			}
		}
	}
}

具体情况如下:

  1. 如果请求容量 大于 两倍现有容量 ,则新容量 直接为请求容量

  2. 否则(请求容量 小于等于 两倍现有容量)

​ 如果 现有容量 小于 256 ,则新容量是原来的两倍

​ 否则:新容量 = 1.25 原容量 + 3/4 阈值 “这个公式给出了从1.25倍增长 过渡到2 倍增长,两者之间的平滑过渡。” 在此情况下,如果发生了溢出,将新容量设置为请求的容量大小

注意:目前仍然存在追加顺序的问题:当前切片的扩容,严格依赖第一个切片的容量,以第一个切片的容量进行计算,如果交换两个切片,两种方式得到的新切片的容量大概率是不一样的

posted @   小星code  阅读(1120)  评论(2编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示