Golang底层原理解析(5)—— slice切片扩容机制

145 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情

生命不息,学习不止

题外话

今天周五了,这两天太阳可能休假了,又是阴天的一天,这个天也太让人犯困了呀,但是一想到明天就可以放假了,一觉睡到自然醒就很激动啊,哈哈哈

image.png

废话不多说,上货

在这里插入图片描述

上回讲了一下slice切片的底层结构和拷贝,今天就来说说slice切片的扩容机制

slice扩容机制

基本都知道数组是一个固定长度的结构,要在初始时声明长度,

而slice切片是动态的,可通过append()函数向切片中追加元素,甚至可以直接追加一个切片来将切片中所有的元素加入进去,举个例子

image.png

可以看到slice切片内的数组越来越多,但slice声明时不可能声明一个无限长的长度,所以一定是有一个默认长度, 当元素到一定数量后会触发扩容

要想明白原理还是直接看源码,负责slice切片扩容的核心函数是 growslice(),核心代码如下

func growslice(et *_type, old slice, cap int) slice {

//...............

newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
   newcap = cap
} else {
   const threshold = 256
   if old.cap < threshold {
      newcap = doublecap
   } else {
    
      for 0 < newcap && newcap < cap {
       
         newcap += (newcap + 3*threshold) / 4
      }
   
      if newcap <= 0 {
         newcap = cap
      }
   }
}

//............
}

可以看到如果向slice切片中添加元素的容量大于原本容量的二倍,就会变成添加后的容量

如果添加后的容量小于原本容量的二倍并小于1024,仍然为原容量的二倍

但如果添加后的容量小于原本容量的二倍并大于1024,则变为原容量的1.25倍

其实growslice()函数的后半部分还根据et对能容量进行了内存对齐

对齐之后会为新的slice预留一部分空间,也就是所说的预留了一部分buffer

最后便是将原slice的元素copy到新的slice切片中,并将新添加的元素加入到新slice切片中

你以为结束了

下一篇我们讲一下append()方法与...

在这里插入图片描述

大家看完发现有什么错误,写在下面吧!跟我黑虎阿福比划比划! 在这里插入图片描述