This is a creation in Article, where the information may have evolved or changed.
Golang Escape Analysis
Introduction to the concept of escape analysis, go how to open the log of escape analysis.
The following information from the Internet, there are errors, please be sure to tell.
Sheepbao 2017.06.10
What is escape analysis
Definitions on a wiki
In compiler optimization, escape analysis are a method for determining the dynamic scope of Pointers-where A pointer can be accessed. It is related to pointer an analysis and a shape analysis.
When a variable (or an object) was allocated in a subroutine, a pointer to the variable can escape to other threads of exec Ution, or to calling subroutines. If An implementation uses tail call optimization (usually required for functional languages), objects could 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 is accessed from undetermined places in th E program-the pointer has "escaped". Pointers can also escape if they is stored in global variables or other data structures this, 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 pro Ven to is restricted only to the current procedure and/or Threa
Presumably, in the compiler optimization theory, Escape analysis is a method to determine the dynamic range of a pointer, which can be used to analyze where a pointer can be accessed in the program. It involves pointer analysis and shape analysis. When a variable (or object) is allocated in a subroutine, a pointer to a variable may escape to the other execution thread, or the subroutine will be called. If you use tail recursion optimization (which is usually required in a functional programming language), the object may also escape into the called subroutine. If a subroutine assigns an object and returns a pointer to the object, the object may be accessed anywhere in the program-so that the pointer succeeds "escaping". If pointers are stored in global variables or other data structures, they can also escape, which is the case of a pointer escaping in the current program. The escape analysis needs to determine where all the pointers can be stored, guaranteeing that the pointer's lifetime is only in the current process or thread.
Usefulness of escape analysis (for performance)
- The biggest benefit should be to reduce the pressure on the GC, the object that does not escape is allocated on the stack, and when the function returns, the resource is reclaimed and no GC tag cleanup is required.
- Because after the escape analysis can determine which variables can be allocated on the stack, the stack is allocated faster than the heap, good performance
- Synchronous elimination, if you define the method of the object has a synchronous lock, but at run time, but only one thread in the access, at this time the escape analysis of the machine code, will remove the synchronous lock run.
Go eliminates heap and stack differences
Go eliminates heap and stack differences to a certain extent, because go is compiled to run the escape analysis to determine whether an object is placed on the stack or on the heap, the object that does not escape is placed on the stack, and may escape the heap.
To open the escape analysis log at Go compile
Open Escape Analysis log is very simple, as long as the compile time to add-gcflags '-m', but we do not allow the compilation of automatic inline function, usually add-lparameters, and ultimately-gcflags '-m -l'
Example:
package main
import (
"fmt"
)
func main() {
s := "hello"
fmt.Println(s)
}
go run -gcflags '-m -l' escape.go
Output:
# command-line-arguments
escape_analysis/main.go:9: s escapes to heap
escape_analysis/main.go:9: main ... argument does not escape
hello
When to escape, when not to escape
Example1:
package main
type S struct{}
func main() {
var x S
y := &x
_ = *identity(y)
}
func identity(z *S) *S {
return z
}
Output:
# command-line-arguments
escape_analysis/main.go:11: leaking param: z to result ~r1 level=0
escape_analysis/main.go:7: main &x does not escape
The first line here indicates that the z variable is "streaming" becauseidentitythe function simply enters a variable and returns the variable as a return output, but the identity does not reference Z, so the variable does not escape, and X is not referenced, and the life cycle is in Mian, and X does not escape and is allocated on the stack.
Example2:
package main
type S struct{}
func main() {
var x S
_ = *ref(x)
}
func ref(z S) *S {
return &z
}
Output:
# command-line-arguments
escape_analysis/main.go:11: &z escapes to heap
escape_analysis/main.go:10: moved to heap: z
The z here is escaping, for the simple reason that go is a value pass, the REF function copy the value of x, pass it to Z, return a pointer to Z, and then be referenced outside the function, indicating that the variable z is declared inside the function and may be accessed by other programs outside the function. So Z escapes, distributes it on the heap
What happens to the variables in the object? Look underneath.
Example3:
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
}
Output:
# command-line-arguments
escape_analysis/main.go:13: &y escapes to heap
escape_analysis/main.go:12: moved to heap: y
Look at the output of the log, where y is escaped, it seems there is no difference in the struct, it is possible to be outside the function of the program Access will escape
Example4:
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
}
Output:
# command-line-arguments
escape_analysis/main.go:12: leaking param: y to result z level=0
escape_analysis/main.go:9: main &i does not escape
The y here does not escape and is allocated on the stack for the same reason and Example1.
Example5:
package main
type S struct {
M *int
}
func main() {
var x S
var i int
ref(&i, &x)
}
func ref(y *int, z *S) {
z.M = y
}
Output:
# command-line-arguments
escape_analysis/main.go:13: leaking param: y
escape_analysis/main.go:13: ref z does not escape
escape_analysis/main.go:10: &i escapes to heap
escape_analysis/main.go:9: moved to heap: i
escape_analysis/main.go:10: main &x does not escape
Here Z does not escape, and I escape, this is because the escape analysis of Go does not know the relationship between Z and I, escape analysis does not know that the parameter y is a member of Z, so it can only be allocated to the heap.
1691 Reads