Golang源码研究:1. 切片扩容问题

文章内容

很多语言中都存在类似动态数组的概念,c++中的vector,Golang里的silce,都是类似动态数组概念。

silce的组成

go
// file: src/runtime/silce.gotype slice struct {      array unsafe.Pointer      len   int      cap   int  }

从源码中可以看到,go中的silce结构体包含三个部分,array len cap.
array传入的是一个指针,用作silce的底层存储数组。len是silce的长度,cap则是底层数组的大小。
当silce的len逐渐逼近cap的时候(len达到cap的一半),将会触发扩容机制。

silce 的扩容

计算下一个cap

go
// nextslicecap computes the next appropriate slice length.func nextslicecap(newLen, oldCap int) int {      newcap := oldCap      doublecap := newcap + newcap      if newLen > doublecap {         return newLen      }        const threshold = 256      if oldCap < threshold {         return doublecap      }      for {         // Transition from growing 2x for small slices         // to growing 1.25x for large slices. This formula              // gives a smooth-ish transition between the two.              newcap += (newcap + 3*threshold) >> 2           // We need to check `newcap >= newLen` and whether `newcap` overflowed.         // newLen is guaranteed to be larger than zero, hence              // when newcap overflows then `uint(newcap) > uint(newLen)`.              // This allows to check for both with the same comparison.              if uint(newcap) >= uint(newLen) {            break         }      }        // Set newcap to the requested cap when      // the newcap calculation overflowed.        if newcap <= 0 {         return newLen      }      return newcap  }

go在设计的时候,对于不同旧cap做了不同的扩容机制。
当 旧cap < 256 时候,将会扩容到旧容量的两倍。
当 旧cap > 256 时候,将会扩容到旧容量的约1.25倍。
这个约1.25倍有点说法。
当大于256时候,newcap=oldcap+(oldcap + 3*256)/4
实际扩容是要比1.25倍稍微大一点的。这是为了使从2倍扩容逐渐过渡到1.25倍扩容。

觉得不错?给作者点个赞吧

分类:Golang 源码研究

评论 (0)

无需注册,留言经站长审核后公开。

加载评论中…

Golang源码研究:1. 切片扩容问题 · Ensan 的博客