Escape analysis of the Go language mechanism (Language mechanics on Escape)

Source: Internet
Author: User
Tags email string
This is a creation in Article, where the information may have evolved or changed. # # Pre-order (Prelude) This series contains four articles that help you understand some of the grammatical structures in the Go language and the design principles behind them, including pointers, stacks, heaps, escape analysis, and value/pointer passing. This is the second article, which mainly introduces heap and escape analysis. The following is the index of this series of articles: 1. [The stack and pointer of the Go language mechanism] (https://studygolang.com/articles/12443) 2. [Escape analysis of Go language mechanism] (https://studygolang.com/articles/12444) 3. [Memory Anatomy of Go language mechanism] (https://studygolang.com/articles/12445) 4. [Go language mechanism of data and grammar design philosophy] (https://studygolang.com/articles/12487) # # Introduction (Introduction) in the first part of the four-part series, I used a value to share to Goroutine The stack example introduces the basis of the pointer structure. And what I'm not saying is that the value exists above the stack. To understand this, you need to learn another location for value storage: heap. With this foundation, you can start learning escape analysis. Escape analysis is the process that the compiler uses to determine the location of the values in your program. Specifically, the compiler performs static code analysis to determine whether an instantiated value of a construct will escape to the heap. In the Go language, you don't have a keyword or function available that allows the compiler to make this decision directly. This decision can only be made by the way you write the code. The # # heap (heaps) heap is the second area of memory, in addition to the stack, where values are stored. The heap is not self-cleaning like a stack, so using this portion of memory can be costly (compared to using stacks). It is important that the cost is related to the GC (garbage collection), which is involved in ensuring that parts of the area are clean. When the garbage collection program runs, it consumes 25% of your available CPU capacity. What's more, it will cause a microsecond "Stop the World" delay. The advantage of having a GC is that you can no longer focus on the management of heap memory, which is a complex and historically error-prone place. In Go, a portion of the value is assigned to the heap. These allocations put pressure on the GC because the values on the heap that are not indexed by the pointer need to be removed. The more values that need to be checked and deleted, the more work will be given each time the GC is run. So, the allocation algorithm works constantly to balance the size of the heap and the speed at which it runs. # # Shared stack (sharing Stacks) in the Go language, pointers in Goroutine are not allowedA stack pointing to another goroutine. This is because when the stack grows or shrinks, the stack memory in the Goroutine is replaced by a new memory. If the runtime needs to trace pointers to other goroutine stacks, it can cause a lot of memory to be managed so that updating pointers to those stacks will make the "Stop the world" problem even worse. Here is an example of a stack that has been replaced several times. Look at lines 2nd and 6th of the output. You will see that the string address value of the stack in the main function has changed two times. [Https://play.golang.org/p/pxn5u4EBSI] (Https://play.golang.org/p/pxn5u4EBSI) # # Escape mechanism (escape mechanics) at any time, a value is shared outside the frame range of the function stack, and it is redistributed on the heap. This is the escape analysis algorithm that discovers these situations and controls this layer of work. The integrity of (memory) is to ensure that access to any value is always accurate, consistent, and efficient. Learn about escape analysis by looking at this language mechanism. [Https://play.golang.org/p/Y_VZxYteKO] (Https://play.golang.org/p/Y_VZxYteKO) # # # 1 "gopackage maintype user struct {name string email string}func main () {u 1: = CreateUserV1 () U2: = CreateUserV2 () println ("U1", &u1, "U2", &u2)}//go:noinlinefunc createUserV1 () User {u: = user{Name: "Bill", Email: "Bill@ardanlabs.com",} println ("V1", &u) return U}//go:noinlinefunc createUserV2 () *user {u: = user{Name: "Bill", Email: "Bill@ardanlabs.com",} println ("V2", &u) return &u} ' I use ' go:noinline ' command to block In the ' main ' function, the compiler uses inline code instead of a function call. Inline (optimization) causes the function call to disappear and complicate the example. I'll introduce the inline build in the next blog postTo the side effects. In table 1, you can see the two different functions that create a ' user ' value and return it to the caller. In function version 1, the return value. List # # 2 "createUserV1 func () user {: = user{18 name:" Bill ", e-mail:" bill@ardanlabs.com ",}2122 println (" V1 ", &u) U24} "' I say this function returns a value because the ' user ' value created by the function is copied and passed to the call stack. This means that a copy of this value is received by the calling function. You can look at the process of the ' user ' value being constructed from line 17th to line 20. Then on line 23rd, a copy of the ' user ' value is passed to the call stack and returned to the caller. After the function returns, the stack looks as follows. # # # figure 1! [] (https://raw.githubusercontent.com/studygolang/gctt-images/master/lang-mechanics/81_figure1.png) you can see in Figure 1, When the call ends ' createUserV1 ', a ' user ' value exists in the stack frame (two functions). In function version 2, a pointer is returned. # # # 3 "func createUserV2 () *user {u: = user{29 Name:" Bill ", Email:" Bill@ardanlabs.com ",}3233 println (" V2 " , &u) return &u35} "' I say this function returns a pointer because the ' user ' value created by the function is shared through the call stack. This means that the calling function receives a copy of the address of the value. You can see that rows 28th through 31 Use the same field values to construct the ' user ' value, but they are different when the 34th row returns. Instead of passing a copy of the ' user ' value to the call stack, the address of the ' user ' value is passed to the call stack. Based on this, you might think that the stack looks like this after the call. # # # Figure 2! [] (https://raw.githubusercontent.com/studygolang/gctt-images/master/lang-mechanics/81_figure2.png) If you see the figure 2 If it really happens, you will meet aProblem. The pointer points to an invalid address space under the stack. When the ' main ' function calls the next function, the memory pointed to will be remapped and will be reinitialized. This is where the escape analysis will begin to remain intact. In this case, the compiler will check that constructing the ' user ' value in the ' createUserV2 ' (function) stack is unsafe, and therefore, instead, constructs (the corresponding) value in the heap. This (a process that is parsed and processed) occurs immediately when line 28th is constructed. # # readability (readability) in the previous blog post, we know that a function can only access its (function stack) space directly, or through a pointer (in the function stack space) to access external memory (outside of the function stack space) by jumping. This means that access to the value escaped to the heap also requires a pointer jump. Remember the ' createUserV2 ' code looks like this: # # # 4 "of Func createUserV2 () *user {u: = user{29 Name:" Bill ", e-mail:" BILL@ARDANLABS.C Om ",}3233 println (" V2 ", &u) return &u35} ' syntax hides what really happens in the code. The variable ' u ' declared in line 28th represents a value of type ' user '. The type construction in Go code does not tell you where the value is in memory. So until the 34th line returns the type, you know that the value needs to be escaped (processed). This means that while ' u ' represents a value of type ' user ', access to the value must be done through a pointer. You can see the stack after the function call like this (Figure 3). # # # Figure 3! [] (https://raw.githubusercontent.com/studygolang/gctt-images/master/lang-mechanics/81_figure3.png) in ' In the createUserV2 ' function stack, the value represented by the variable ' u ' is present in the heap, not the stack. This means that when you access a value with ' U ', you use the pointer to access it instead of directly. You might think, why not let ' u ' become a pointer, after all, access to the value it represents requires the use of pointers? # # # 5 "func createUserV2 () *user {u: = &user{29 Name:" Bill ", e-mail:" bill@ardanlabs.com ",}3233 println ("V2", u) return U35} "If you do this, it will make your code lack important readability. (Let's) leave the entire function for a second, focusing only on ' return '. # # # 6 ' return u35} ' What does this ' return ' tell you? It illustrates the return of a copy of the ' U ' value to the call stack. However, when you use the ' & ' operator, what does ' return ' tell you? # # # 7 ' &u35} ' thanks to the ' & ' operator, ' return ' tells you ' U ' is being shared to the caller, so it has escaped into the heap. Remember, when you read the code, the pointer is for sharing, and the ' & ' operator corresponds to the word "sharing". This is very useful when it comes to readability, and this is part of what you don't want to lose. # # # 8 ' $ var u *user02 err: = json. Unmarshal ([]byte (R), &u), return u, err ' "to make it work, you must give (function) ' JSON by sharing the pointer variable (in the way). Unmarshal '. ' JSON. Unmarshal ' call creates a ' user ' value and assigns its address to the pointer variable. Https://play.golang.org/p/koI8EjpeIx Code Explanation: 01: Create a pointer of type ' user ' with null value. 02: With function ' json. The Unmarshal ' function shares a pointer. 03: Returns a copy of ' U ' to the caller. This is not very well understood, ' user ' value is ' json. The Unmarshal ' function is created and shared to the caller. How do you use syntactic semantics to change readability during construction? # # # 9 ' $ var u user02 err: = json. Unmarshal ([]byte (R), &u) in return &u, err ' ' Code explanation: 01: Create a variable of type ' user ' with a value of NULL. 02: With function ' json. Unmarshal ' function shares ' u '. 03: Share ' U ' with the caller. It's very well understood here. Line No. 02 shares the ' user ' value to ' JSON ' in the call stack. Unmarshal ', in line No. 03 ' user ' value is shared to the caller. This sharing process will cause the ' user ' value to escape. When building a value, use value semantics and use the readability of the ' & ' operator to clarify how values are shared。 # # Compiler report (Compiler Reporting) to see the compiler's decision about escape analysis, you can have the compiler provide a report. You only need to open the '-gcflags ' switch when calling ' Go build ' and bring the '-m ' option. In fact, you can use 4 '-m ' in total, and (but) more than 2 levels of information is already too much. I will use 2 '-M ' levels. # # # list "shell$ go Build-gcflags"-m-m "./main.go:16:cannot inline createuserv1:marked Go:noinline./main.go:27:cann OT inline createuserv2:marked go:noinline./main.go:8: cannot inline main:non-leaf function./main.go:22:createuserv1 &A Mp;u does not escape./main.go:34: &u escapes to Heap./main.go:34:from ~r0 (return) at./main.go:34./main.go:31:moved To Heap:u./main.go:33:createuserv2 &u does not escape./main.go:12:main &U1 does not Escape./main.go:12:main & AMP;U2 does not escape "you can see whether the compiler reports the decision to escape processing. What does the compiler say? Take a look at the referenced ' createUserV1 ' and ' createUserV2 ' functions. List of # # # "createUserV1 func () User {+ U: = user{18 Name:" Bill ", e-mail:" bill@ardanlabs.com ",}2122 println (" V1 " , &u) u24}27 func createUserV2 () *user {$ u: = user{29 Name: "Bill", e-mail: "Bill@ardanlabs.com", 31}3233 println ("V2", &u) return &u35} "starts from this line in the report. # # # list "./main.go:22:createuserv1 &u does not escape" this is said that the function ' createUserV1 ' call ' println ' does not cause the ' user ' value to escape to the heap. This must be checked because it will be shared with the function ' println ' (' U '). Next look at these lines in the report. # # # list "shell./main.go:34: &u escapes to Heap./main.go:34:from ~r0 (return) at./main.go:34./main.go:31:moved to Heap:u./main.go:33:createuserv2 &u does not escape "is said to be of type ' user ', and the value of ' U ' is assigned in line 31st because the ' return ' of line 34th escapes. The last line is that, as before, calling ' println ' in line 33 will not cause the ' user ' value to escape. Reading these reports can be confusing, depending on whether the type of the variable being discussed is based on a value type or a pointer type. Change ' u ' to a pointer-type ' *user ' instead of the previous named type ' user '. # # # # createUserV2 () func-*user {$ u: = &user{29 Name: "Bill", e-mail: "bill@ardanlabs.com",}3233 printl N ("V2", U) return u35} "to generate the report again. # # # list "shell./main.go:30: &user literal escapes to Heap./main.go:30:from U (assigned) at./main.go:28./main.go:3 0:from ~r0 (return) at./main.go:34 "Now reports that the pointer type ' *user ' is assigned in 28 rows, ' U ' references the ' user ' value because 34 rows of ' return ' escapes. # # The conclusion value cannot be determined at the time of constructionWhere it will exist. Only when a value is shared does the compiler decide what to do with the value. When you share a value on the stack when you call it, it escapes. In the next article you will explore other reasons for a value escape. These articles attempt to guide you through the selection of values or pointers for a given type. Each approach has (corresponding) benefits and (additional) overhead. The value that remains on the stack reduces the pressure on the GC. However, different replicas need to be stored, tracked, and maintained. Placing a value on a heap pointer increases the pressure on the GC. However, there are also its benefits, with only one value that needs to be stored, tracked, and maintained. (In fact,) the key is how to maintain proper, consistent and balanced (overhead) use.

Via:https://www.ardanlabs.com/blog/2017/05/language-mechanics-on-escape-analysis.html

Author: William Kennedy Translator: gogeof proofreading: polaris1119

This article by GCTT original compilation, go language Chinese network honor launches

This article was originally translated by GCTT and the Go Language Chinese network. Also want to join the ranks of translators, for open source to do some of their own contribution? Welcome to join Gctt!
Translation work and translations are published only for the purpose of learning and communication, translation work in accordance with the provisions of the CC-BY-NC-SA agreement, if our work has violated your interests, please contact us promptly.
Welcome to the CC-BY-NC-SA agreement, please mark and keep the original/translation link and author/translator information in the text.
The article only represents the author's knowledge and views, if there are different points of view, please line up downstairs to spit groove

1737 reads ∙1 likes
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.