Go中切片扩容原理
廢話不多說直接看源碼
// src/runtime/slice.go func growslice(et *_type, old slice, cap int) slice { // ...省略部分newcap := old.capdoublecap := newcap + newcapif cap > doublecap {newcap = cap} else {if old.len < 1024 {newcap = doublecap} else {// Check 0 < newcap to detect overflow// and prevent an infinite loop.for 0 < newcap && newcap < cap {newcap += newcap / 4}// Set newcap to the requested cap when// the newcap calculation overflowed.if newcap <= 0 {newcap = cap}}} // ...省略部分 }四個重要的屬性
- cap : 需要的容量
- old.cap : 舊切片的容量
- newcap : 最終要申請的容量
- doublecap : old.cap的兩倍
看代碼就知道下方的擴容的機制
- 當需要的容量cap大于兩倍舊容量doublecap時, 我們申請的新容量就是需要的容量
- 當需要的容量cap小于兩倍舊容量doublecap時, 判斷是否舊切片的長度小于1024, 如果小于1024, 那么newcap = 兩倍舊cap, 直接翻倍
- 當舊切片的長度 >= 1024時, 會反復地增加25%,直到新容量newcap超過所需要的容量cap。 其中newcap > 0 是防止int類型溢出, 如果溢出那么就直接newcap = cap(需要的容量)
一點個人思考:
如何求得所需要的容量cap ?
咱們來看兩個例子
第一個 :
func main() {arr := []int{1, 2, 3, 4}fmt.Println("擴容前容量是 : ", cap(arr))arr = append(arr, []int{5, 6, 7, 8, 9}...)fmt.Println("擴容后容量是 : ", cap(arr)) }擴容前的容量是 4
當我們追加了5個元素之后, 按理來說需要的容量應該是9 對不對 ?
姑且算是cap = 9
在我們上面的growslice函數中, 如果按照cap是9來算的話
最后的newcap 應該是 等于 9
但是打印結果是
再來看另外一個例子
對于這個自定義切片的結果就是9
結論 : 所以我推測, golang內部對于內置類型, 有著自己的處理方式, 所以第一個例子我們對于int類型的切片append, 應該是進來的cap就是10, 在其他地方做了處理, 可能方便于內存對齊.
對我我們自定義類型的切片就是直接 cap = oldcap + append()函數中追加的容量
總結
- 上一篇: 从浏览器输入URL到最终看到页面, 这其
- 下一篇: Go中的Map实现机制