什么是逃逸分析
In compiler optimization, escape analysis is a method for determining the dynamic scope of pointers - where in the program a pointer can be accessed. It is related to pointer analysis and shape analysis.
When a variable (or an object) is allocated in a subroutine, a pointer to the variable can escape to other threads of execution, or to calling subroutines. If an implementation uses tail call optimization (usually required for functional languages), objects may also be seen as escaping to called subroutines. If a language supports first-class continuations (as do Scheme and Standard ML of New Jersey), portions of the call stack may also escape.
If a subroutine allocates an object and returns a pointer to it, the object can be accessed from undetermined places in the program — the pointer has "escaped". Pointers can also escape if they are stored in global variables or other data structures that, in turn, escape the current procedure.
Escape analysis determines all the places where a pointer can be stored and whether the lifetime of the pointer can be proven to be restricted only to the current procedure and/or threa
逃逸分析是一種確定指針動(dòng)態(tài)范圍的方法析砸,可以分析在程序的哪些地方可以訪問(wèn)到指針露懒。它涉及到指針?lè)治龊托螤罘治觥?當(dāng)一個(gè)變量(或?qū)ο?在子程序中被分配時(shí)揩尸,一個(gè)指向變量的指針可能逃逸到其它執(zhí)行線程中,或者去調(diào)用子程序。如果使用尾遞歸優(yōu)化(通常在函數(shù)編程語(yǔ)言中是需要的),對(duì)象也可能逃逸到被調(diào)用的子程序中遭庶。 如果一個(gè)子程序分配一個(gè)對(duì)象并返回一個(gè)該對(duì)象的指針承匣,該對(duì)象可能在程序中的任何一個(gè)地方被訪問(wèn)到——這樣指針就成功“逃逸”了蓖乘。如果指針存儲(chǔ)在全局變量或者其它數(shù)據(jù)結(jié)構(gòu)中,它們也可能發(fā)生逃逸韧骗,這種情況是當(dāng)前程序中的指針逃逸嘉抒。 逃逸分析需要確定指針?biāo)锌梢源鎯?chǔ)的地方,保證指針的生命周期只在當(dāng)前進(jìn)程或線程中袍暴。
逃逸分析的用處(為了性能)
最大的好處應(yīng)該是減少gc的壓力众眨,不逃逸的對(duì)象分配在棧上,當(dāng)函數(shù)返回時(shí)就回收了資源容诬,不需要gc標(biāo)記清除娩梨。
因?yàn)樘右莘治鐾旰罂梢源_定哪些變量可以分配在棧上,棧的分配比堆快览徒,性能好狈定。
同步消除,如果你定義的對(duì)象的方法上有同步鎖习蓬,但在運(yùn)行時(shí)纽什,卻只有一個(gè)線程在訪問(wèn),此時(shí)逃逸分析后的機(jī)器碼躲叼,會(huì)去掉同步鎖運(yùn)行芦缰。
go消除了堆和棧的區(qū)別
go在一定程度消除了堆和棧的區(qū)別,因?yàn)間o在編譯的時(shí)候進(jìn)行逃逸分析枫慷,來(lái)決定一個(gè)對(duì)象放棧上還是放堆上让蕾,不逃逸的對(duì)象放棧上,可能逃逸的放堆上或听。
開(kāi)啟逃逸分析日志
編譯參數(shù)加入 -gcflags '-m -l'
package main
type S struct {
M *int
}
func main() {
var i int
refStruct(i)
}
func refStruct(y int) (z S) {
z.M = &y
return z
}
? escapeAnalyze go build -gcflags '-m -l' main.go
# command-line-arguments
./main.go:13:11: &y escapes to heap
./main.go:12:16: moved to heap: y
? escapeAnalyze
日志的輸出表明探孝,y是逃逸了,因?yàn)?z 引用了 y誉裆,y 本身是一個(gè) i 的副本顿颅。