Go escape analysis

Go escape analysis

Heap and stack

To understand what are some of the basics of escape analysis will involve heap and stack, if we can simply forget the students recap:

  • Heap (Heap): Generally is artificially managed manually, manual application, distribution, release. Unpredictable heap for memory allocation size, this also means that the price to pay is allocated slow, and the formation of memory fragmentation.

  • Stack (Stack): managed by the compiler, automatic application, distribution, release. Generally not too big, so stack allocation and recovery very fast; we have a common function parameters (the number of different platforms to allow different storage), local variables, etc. will be stored on the stack.

Stack allocate memory only requires two CPU instruction: "PUSH" and "RELEASE", allocation and release; while the heap memory allocated first need to find an appropriate size memory block, to be released later by the garbage collector can.

Popular metaphor to say that as we go to a restaurant for dinner, just a la carte (issue apply) - "Chichi Chi (using memory) -" Yes, and ran the rest to restaurants (OS automatic recovery), and just like cooking at home, large home, to buy what little food, every step needed to achieve their own, but freedom will be much larger.

 

What is the escape analysis

The compiler optimization theory, the escape analysis is a method of determining the dynamic range of a pointer, which is simply the analysis procedure where access to the pointer.

Beyond Simply put, Go through doing escape analysis (escape analysis) compiler to decide where to put an object on the stack or heap put, do not put an object on the stack of escape, escape might put on the heap; that is, I find 变量after the exit function is not used, then throw put on the stack after stack memory allocated on the heap and recover much faster than; on the contrary, common variable within the function through 逃逸分析, found after the function exits 变量as well as in other places the reference, it will be 变量allocated on the heap. Do DAMA (where people need me, I'll ~ ~ where to go, cry a party member).

 

Why do I need escape analysis

ok, complete understanding and the respective advantages and disadvantages, we can better know the 逃逸分析purpose of the existence of:

  1. Reduce gcstress, variables on the stack, with the function exits after the system is recovered directly, without gcmark and then cleared.

  2. Reduce memory fragmentation.

  3. Reduce the overhead of allocated heap memory, improve the operating speed of the program.

 

How to determine whether the escape

In Gothe variable to determine whether the escape escape by analyzing the log, open the escape analysis log:

go run -gcflags '-m -l' main.go
  • -mIt will print optimization strategy escape analysis, in fact, can be used up to a total of four -m, but the large amount of information, usually with one on it.

  • -lInline function is disabled, disable the swap where 内联better when viewed escape, to reduce interference.

 

Escape Case

Case I: Take the escape occurred address

package main

type UserData struct {
Name  string
}

func main() {
var info UserData
info.Name = "WilburXu"
_ = GetUserInfo(info)
}

func GetUserInfo(userInfo UserData) *UserData {
return &userInfo
}

The implementation of go run -gcflags '-m -l' main.gothe returns the following results:

# command-line-arguments
.\main.go:14:9: &userInfo escapes to heap
.\main.go:13:18: moved to heap: userInfo

GetUserInfo inside the function variable userInfoescape the heap (memory space allocated to the heap).

GetUserInfo return value of the function * UserData pointer type, then the value of the variable userInfoaddress returned, then the compiler determines whether the value of the function may be used outside, it will be assigned to the heap, so variables userInfoon escapes.

Optimization

func main() {
var info UserData
info.Name = "WilburXu"
_ = GetUserInfo(&info)
}

func GetUserInfo(userInfo *UserData) *UserData {
return userInfo
}
# command-line-arguments
.\main.go:13:18: leaking param: userInfo to result ~r1 level=0
.\main.go:10:18: main &info does not escape

Taking the address of a variable, it may be assigned to the heap. But the compiler escape analysis, if found to after the function returns, this variable is not referenced, or will be allocated on the stack. A set of address-breaks, subsidies on trying to cheat?

The compiler playfully said: Too young, Too Cool ...!

 

Case II: undetermined type

package main

type User struct {
name interface{}
}

func main() {
name := "WilburXu"
MyPrintln(name)
}

func MyPrintln(one interface{}) (n int, err error) {
var userInfo = new(User)
userInfo.name = one // 泛型赋值 逃逸咯
return
}

The implementation of go run -gcflags '-m -l' main.gothe returns the following results:

# command-line-arguments
./main.go:12:16: leaking param: one
./main.go:13:20: MyPrintln new(User) does not escape
./main.go:9:11: name escapes to heap

There may be some students wonder, MyPrintlnconvenient and not referenced in function, why the change namewill be assigned to on it?

On a case we know, the ordinary way to go "cheat subsidy" smart Ling Lee compiler is not "cheated Oh"; but for the interfacetype, unfortunately, the compiler at compile time is difficult to know in call or assignment process structure function would be how type, and therefore can only be assigned to on.

Optimization

The structure Usermember nametype, a function of MyPringLnthe parameter onetype to stringthe results:

# command-line-arguments
./main.go:12:16: leaking param: one
./main.go:13:20: MyPrintln new(User) does not escape

Extensive Analysis

For the analysis of two cases, we can also decompile command go tool compile -S main.goview, you will find if interfacetype, main main function after compiling 额外more than the following instructions:

# main.go:9 -> MyPrintln(name)
0x001d 00029 (main.go:9) PCDATA $2, $1
0x001d 00029 (main.go:9) PCDATA $0, $1
0x001d 00029 (main.go:9) LEAQ go.string."WilburXu"(SB), AX
0x0024 00036 (main.go:9) PCDATA $2, $0
0x0024 00036 (main.go:9) MOVQ AX, ""..autotmp_5+32(SP)
0x0029 00041 (main.go:9) MOVQ $8, ""..autotmp_5+40(SP)
0x0032 00050 (main.go:9) PCDATA $2, $1
0x0032 00050 (main.go:9) LEAQ type.string(SB), AX
0x0039 00057 (main.go:9) PCDATA $2, $0
0x0039 00057 (main.go:9) MOVQ AX, (SP)
0x003d 00061 (main.go:9) PCDATA $2, $1
0x003d 00061 (main.go:9) LEAQ ""..autotmp_5+32(SP), AX
0x0042 00066 (main.go:9) PCDATA $2, $0
0x0042 00066 (main.go:9) MOVQ AX, 8(SP)
0x0047 00071 (main.go:9) CALL runtime.convT2Estring(SB)

For the Go汇编语法unfamiliar can refer Golang compilation Quick Guide

 

to sum up

Do not blindly use a pointer variable as a parameter, although it will reduce the copy operation. When the parameter is variable but in fact itself when copying is performed on the stack operation, the variable cost than dynamically allocated on the heap escape much less memory.

Go compiler just as a clever 孩子general, most of the time on escape analysis process in question are impressive, but sometimes 闹性子analysis when processing is very rough or completely abandoned, after all, this is the nature of the child is not it? So we also need to observe a lot of the time writing code, a lot of attention.

 

Reference article

Golang escape analysis

 

 

 

 

Guess you like

Origin www.cnblogs.com/wilburxu/p/11184604.html