從內存分配策略(堆、棧)的角度分析,函數傳遞指針真的比傳值效率高嗎?git
持續更新於個人 Github ,歡迎 Stargithub
介紹golang
對於初學者,確定不少同窗在糾結:shell
分析bash
要找到區別,那確定須要下功夫,那就從 Golang 的實現機制中來分析吧。首先,在Golang 中有一個很重要的概念那就是 逃逸分析(Escape analysis),所謂的逃逸分析指由編譯器決定內存分配的位置。閉包
最終程序的執行效率和這個兩種分配規則是有這重要關聯的,而傳值和傳指針的主要區別在於底層值是否須要拷貝,表面上看傳指針不涉及值拷貝,效率確定更高。可是實際狀況是指傳針會涉及到變量逃逸到堆上,並且會增長GC的負擔,因此本文咱們要作的內容就是進行 逃逸分析 ,按照慣例先上結論。函數
每種方式都有各自的優缺點,棧上的值,減小了 GC 的壓力,可是要維護多個副本,堆上的指針,會增長 GC 的壓力,但只需維護一個值。所以選擇哪一種方式,依據本身的業務狀況參考這個標準進行選擇。性能
先上一段代碼分析下ui
// escape.go
package main
type person struct {
name string
age int
}
func main() {
makePerson(32, "艾瑪·斯通")
showPerson(33, "楊冪")
}
func makePerson(age int, name string) *person {
maliya := person{name, age}
return &maliya
}
func showPerson(age int, name string) person {
yangmi := person{name, age}
return yangmi
}
複製代碼
運行以下命令,進行逃逸分析spa
go build -gcflags="-m -m -l" escape.go
複製代碼
輸出結果:
Escape/Escape.go:15:9: &maliya escapes to heap
Escape/Escape.go:15:9: from ~r2 (return) at Escape/Escape.go:15:2
Escape/Escape.go:14:2: moved to heap: maliya
Escape/Escape.go:13:40: leaking param: name to result ~r2 level=-1
Escape/Escape.go:13:40: from person literal (struct literal element) at Escape/Escape.go:14:18
Escape/Escape.go:13:40: from maliya (assigned) at Escape/Escape.go:14:9
Escape/Escape.go:13:40: from &maliya (address-of) at Escape/Escape.go:15:9
Escape/Escape.go:13:40: from ~r2 (return) at Escape/Escape.go:15:2
Escape/Escape.go:18:39: leaking param: name to result ~r2 level=0
Escape/Escape.go:18:39: from person literal (struct literal element) at Escape/Escape.go:19:18
Escape/Escape.go:18:39: from yangmi (assigned) at Escape/Escape.go:19:9
Escape/Escape.go:18:39: from ~r2 (return) at Escape/Escape.go:20:2
複製代碼
從結果中咱們看到變量 &maliya 發生了逃逸,變量 yangmi 沒有逃逸
&maliya escapes to heap from ~r2 (return) at Escape/Escape.go:15:2
moved to heap: maliya
複製代碼
因此 makePerson 返回的是指針類型,發生了逃逸,而showPerson 返回的是值類型沒有逃逸。
關於變量逃逸的狀況還有不少,網上有不少分析的文章,就不一一舉例了,直接給出結論: