前言

相信很多goher都知道slice在append时如果超出了原来的容量时会翻倍扩容。

疑问

这种翻倍扩容是可持续的吗?比如slice已经4GB了,这个时候难道会直接申请8GB?带着这个疑问我们直接去源码里找答案。

真相

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// src/runtime/slice.go
// go version 1.13
func growslice(et *_type, old slice, cap int) slice {
// ...省略部分
    newcap := old.cap
    doublecap := newcap + newcap
    if cap > doublecap {
        newcap = cap
    } else {
        //原切片长度低于1024时直接翻倍
        if old.len < 1024 {
            newcap = doublecap
        } else {
            // Check 0 < newcap to detect overflow
            // and prevent an infinite loop.
            //原切片长度大于等于1024时,每次只增加25%,直到满足需要的容量
            for 0 < newcap && newcap < cap {
                newcap += newcap / 4
            }
            // Set newcap to the requested cap when
            // the newcap calculation overflowed.
            if newcap <= 0 {
                newcap = cap
            }
        }
    }
// ...省略部分
}

源码里清楚的展示出了slice的长度在超过一个阈值(这里是1024)后便不再翻倍,而是每次以25%的幅度增长,直到满足所需的容量。