golang slice (切片) 扩容机制详解(1.18版本后)

发布时间 2023-07-19 21:09:41作者: 小星code

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。这个公式给出了两者之间的平滑过渡。
				newcap += (newcap + 3*threshold) / 4
                //新容量是 = 1.25 原容量 + 3/4 阈值 (192)
                
              //当newcap计算溢出时,将newcap设置为请求的上限。
			if newcap <= 0 {   // 如果发生了溢出,将新容量设置为请求的容量大小
				newcap = cap
			}
		}
	}
}

具体情况如下:

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

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

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

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