Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to understand Escape Analysis in Go language

2025-02-23 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly explains "how to understand escape analysis in Go language". The content of the explanation is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn "how to understand escape analysis in Go language".

Catalogue

1. Introduction of escape analysis

2. Where is the memory allocation in Go?

3. The difference of memory allocation between Go and C++

4. Escape analysis operation

5. An extended example of escape analysis

1. Introduction of escape analysis

Computer students all know that in the principle of compilation, the method of analyzing the dynamic range of pointers is called escape analysis. Generally speaking, when an object's pointer is referenced by multiple methods or threads, we call the pointer an "escape".

The escape analysis of Go language is the optimization and simplification of memory management after the compiler performs static code analysis, which can determine whether a variable is assigned to the stack or stack.

Those of you who have written about C _ new + should know that using the classic malloc and new functions can allocate a piece of memory on the heap. The task of using and reclaiming (destroying) this piece of memory is not handled properly among programmers, and memory leaks are likely to occur.

2. Where is the memory allocation in Go?

But in the go language, there is basically no need to worry about memory leaks, because memory recycling has been handled for us in the Go language (GC recycling mechanism). Although there are new functions, the memory obtained by using the new function is not necessarily on the heap. The difference between heap and stack is blurred to programmers, all of which is done by the Go compiler behind our backs.

The most basic principle of Go language escape analysis is that if a function returns a reference to a variable, it will escape.

Simply put, the compiler analyzes the characteristics and life cycle of the code. Variables in Go are assigned to the stack only if the compiler can prove that they will no longer be referenced after the function returns. In other cases, they are assigned to the heap.

There is no keyword or function in the Go language that allows the variable to be assigned directly to the heap by the compiler. Instead, the compiler analyzes the code to decide where to assign the variable.

Taking an address on a variable may be assigned to the heap. However, after the compiler does escape analysis, if it is observed that this variable will not be referenced after the function returns, it will still be assigned to the stack.

The compiler decides whether or not to escape based on whether the variable is externally referenced:

If it is not referenced outside the function, it is given priority to the stack area.

If there is a possibility of a reference outside the function, it will be placed in the heap area

In order to improve efficiency, we often upgrade pass-by-value to pass-by-reference in order to improve efficiency when we write Cmax Candle + code, in an attempt to avoid the constructor running and return a pointer directly.

As you will remember, there is a big hidden hole: a local variable is defined inside the function, and then the address (pointer) of the local variable is returned. These local variables are allocated on the stack (static memory allocation). Once the function is executed, the memory occupied by the variable will be destroyed, and any action on this return value (such as dereferencing) will disrupt the running of the program. even cause the program to crash directly. For example, the following code:

Int * foo (void) {int t = 3; return & t;}

Some students may know the above pit and use a smarter approach: use the new function to construct a variable (dynamic memory allocation) inside the function, and then return the address of the variable. Because the variable is created on the heap, the function is not destroyed when it exits.

But is that all right? When and where should the object from new be delete? The caller may forget delete or pass the return value directly to another function, and then can no longer delete it, that is, a memory leak has occurred. About this pit, you can take a look at Article 21 of "Effective C++", which is very good!

3. The difference of memory allocation between Go and C++

The problems that will be encountered in the above-mentioned CUniverse + are highly praised as a language feature in Go, which can solve the above difficulties!

The dynamically allocated memory in Cracket + requires us to release it manually, which leads to a problem: some memory is not handled properly or reclaimed in a timely manner, resulting in memory leaks.

But the advantage is that developers can manage memory on their own.

Go garbage collection makes heaps and stacks transparent to programmers. It really frees the hands of programmers so that they can focus on their business and write code "efficiently". Leave those complex mechanisms of memory management to the compiler, and programmers can enjoy life.

4. Escape analysis operation

The "coquettish operation" of escape analysis assigns variables reasonably to where they are supposed to go. Even if you are using new to apply for the memory, if I find that you are unexpectedly useless after quitting the function, then I will throw you on the stack, after all, the memory allocation on the stack is much faster than on the heap; on the contrary, even if you are only an ordinary variable on the surface, but after escape analysis found that there are other places in the reference after exiting the function, then I will assign you to the heap.

If variables are assigned to the heap, the heap does not clean up automatically like the stack. It causes Go to do garbage collection frequently, which takes up a large amount of system overhead (25% of CPU capacity).

Compared with the stack, the heap is suitable for memory allocation of unpredictable size. But the price is slow allocation and memory fragmentation. Stack memory allocation can be very fast. Stack allocation of memory requires only two CPU instructions: "PUSH" and "RELEASE", which are allocated and freed, while heap allocation of memory first needs to find a block of memory of the right size, and then it can be released through garbage collection.

Through escape analysis, the variables that do not need to be assigned to the heap can be allocated directly to the stack as far as possible. Fewer variables on the heap will reduce the overhead of allocating heap memory, reduce the pressure on gc, and improve the running speed of the program.

5. An extended example of escape analysis

Extension 1: how do I see if a variable has escaped? Two methods: use the go command to view the escape analysis results, and disassemble the source code

For example, use this example:

Package mainimport "fmt" func foo () * int {t: = 3 return & t;} func main () {x: = foo () fmt.Println (* x)}

Use the go command:

Go build-gcflags'- m-l' main.go

The purpose of adding-l is to prevent the foo function from being inlined. Get the following output:

# Command line variable src/main.go:7:9: & t escapes to heapsrc/main.go:6:7: moved to heap: tsrc/main.go:12:14: * x escapes to heapsrc/main.go:12:13: main. Argument does not escape

The variable t in the foo function escaped, as we expected. What puzzles us is why the x in the main function also escapes. This is because some function arguments are of type interface, such as fmt.Println (a... Interface {}), it is difficult to determine the specific type of its parameters during compilation, and escapes also occur.

The disassembly code is difficult to understand, so I won't talk about it here.

Extension 2: did the variables in the following code escape?

Let's take a look at example 1:

Package maintype S struct {} func main () {var x S _ = identity (x)} func identity (x S) S {return x}

Analysis: GE language functions are passed through the value, when calling the function, copy a parameter directly on the stack, there is no escape.

Let's take a look at example 2:

Package maintype S struct {} func main () {var x S y: = & x _ = * identity (y)} func identity (z * S) * S {return z}

Analysis: the input of the identity function is treated directly as a return value, and z does not escape because there is no reference to z. The reference to x also does not escape from the scope of the main function, so x does not escape.

Continue to look at example 3:

Package maintype S struct {} func main () {var x S _ = * ref (x)} func ref (z S) * S {return & z}

Analysis: Z is a copy of x, and z is referenced in the ref function, so z cannot be put on the stack, otherwise outside the ref function, how to find z through reference, so z must escape to the heap. Although the result of ref is discarded directly in the main function, the compiler of Go is not smart enough to analyze this situation. There is no reference to x, so there is no escape from x.

There is also example 4: what if you assign a reference to a member of a structure?

Package maintype S struct {M * int} func main () {var i int refStruct (I)} func refStruct (y int) (z S) {z.M = & y return z}

Analysis: the refStruct function takes a reference to y, so y escapes.

Finally, take a look at example 5:

Package maintype S struct {M * int} func main () {var i int refStruct (& I)} func refStruct (y * int) (z S) {z.M = y return z}

Analysis: I is referenced in the main function and passed to the refStruct function. The reference to I has been used in the scope of the main function, so I did not escape. Compared with the previous example, there is a slight difference, but the resulting program effect is different: in example 4, I is allocated first in the main stack frame, then in the refStruct stack frame, and then escapes to the heap, allocating once to the heap for a total of three times. In this case, I is assigned only once and then passed by reference.

Thank you for your reading, the above is the content of "how to understand the escape analysis in Go language". After the study of this article, I believe you have a deeper understanding of how to understand the escape analysis in Go language, and the specific usage needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report