眾所周知,golang中切片在容量不足時會自動擴容,那麼擴容後的切片容量到底是多少呢?
瀏覽了很多文章,絕大多數給出的答案都是小於1024時為原來的2倍,大於1024時是1.25倍,因為原始碼中這樣一段**
// src/runtime/slice.go:100
newcap := old.
cap doublecap := newcap + newcap
ifcap
> doublecap
else
else
}}
看上去的確是這樣,但是,newcaps的計算並沒有結束,所以,上面的說法嚴謹的來說是錯誤的。
newcaps在進行了翻倍或者是增加25%後,還會進行接下來的計算
// src/runtime/slice.go:82
func
growslice
(et *_type, old slice,
capint
) slice
// ......
}
et代表slice中的元素型別,old是擴容前的切片,cap是擴容後的至少需要的最小容量,即old.caps + 本次新增的元素數量,ptrsize是指乙個指標的大小,在64位中為8。到這裡後會根據et.size的大小進入roundupsize去調整newcaps的大小。當入參小於32768時,主要依賴class_to_size,size_to_class8或size_to_class128這三個陣列中的兩個去調整newcaps。
// src/runtime/msize.go:35
func
roundupsize
(size uintptr
)uintptr
else
}// _pagesize = 1 << 13
if size+_pagesize < size
return
round
(size, _pagesize)
}
// src/runtime/stubs.go:289
func
round
(n, a uintptr
)uintptr
var size_to_class8 =
[smallsizemax/smallsizediv +1]
uint8
var size_to_class128 =
[(_maxsmallsize-smallsizemax)
/largesizediv +1]
uint8
var class_to_size =
[_numsizeclasses]
uint16
舉個例子:
package main
import
"fmt"
func
main()
s =(s,4,5
,6) fmt.
printf
("len=%d, cap=%d"
,len
(s),
cap(s)
)}
最後得到的結果為
len=5, cap=6
newcap =
int(capmem / et.size)
Go 中切片擴容的策略
如果切片的容量小於 1024 個元素,於是擴容的時候就翻倍增加容量。上面那個例子也驗證了這一情況,總容量從原來的4個翻倍到現在的8個。一旦元素個數超過 1024 個元素,那麼增長因子就變成 1.25 即每次增加原來容量的四分之一。注意 擴容擴大的容量都是針對原來的容量而言的,而不是針對原來陣列的長度...
golang中切片 slice 的坑
golang中陣列的長度是不可以變得,但是某些場合就不使用了,go提供了一種靈活,功能強悍的型別 切片,切片中有兩種概念 一種是len長度,二是cap容量,長度是已經被賦值的最大下標 1,可以通過len函式獲得切片的長度。容量是指切片最大可容納多少個元素,可以通過cap函式獲得,切片是引用型別,因此...
golang中slice的擴容機制
在golang中slice是乙個指向陣列的指標結構體。這個結構體有三個屬性 其概念為 動態陣列 及陣列的容量大小 cap 會隨著陣列的實際大小 size 變化而變化 擴容 擴容機制 如果切片的容量小於1024個元素,那麼擴容的時候slice的cap就翻番,乘以2 一旦元素個數超過1024個元素,則乘...