對於一些初學者,自知道 Go 裏面的 array 以 pass-by-value 方式傳遞後,就莫名地引發 「恐慌」。外加諸多文章未做說明,就建議用 slice 代替 array,企圖避免數據拷貝,提高性能。實際上,此作法有待商榷。某些時候怕會拔苗助長,倒形成沒必要要的性能損失。函數
用個簡單的示例說明。性能
package main import ( "fmt" ) const capacity = 1024 func array() [capacity]int { var d [capacity]int for i := 0; i < len(d); i++ { d[i] = 1 } return d } func slice() []int { d := make([]int, capacity) for i := 0; i < len(d); i++ { d[i] = 1 } return d } func main() { fmt.Println(array()) fmt.Println(slice()) }
代碼很簡單,兩個函數分別返回 「內容相同」 的 array 和 slice。爲避免編譯器優化,特填充了所有數據,以模擬 「真實」 數據複製行爲。接下來,看看性能測試對比。測試
package main import ( "testing" ) func BenchmarkArray(b *testing.B) { for i := 0; i < b.N; i++ { _ = array() } } func BenchmarkSlice(b *testing.B) { for i := 0; i < b.N; i++ { _ = slice() } }
這結果怕是顛覆了最初認知。array 非但擁有更好的性能,還避免了堆內存分配,也就是說減輕了 GC 壓力。爲何會這樣?優化
熟悉彙編的,怕是很容易看出來。函數 array 返回值的複製只需用 "CX + REP" 指令就可完成。spa
整個 array 函數徹底在棧上完成,而 slice 函數則需執行 makeslice,繼而在堆上分配內存,這就是問題所在。code
對於一些短小的對象,複製成本遠小於在堆上分配和回收操做。對象
Go Proverbs: A little copying is better than a little dependency.圖片
最新動態,請掃碼關注
內存