Whether the go variable is allocated in the heap or stack

Source: Internet
Author: User

Recently trying to optimize the allocation of small objects, found a very strange problem: This code will allocate objects on the heap.

Package main

Import (
    "FMT"
)

func main () {
    var a [1]int
    c: = a[:]
    fmt. Println (c)
}

See Assembly code

Go tool compile-s Test.golang "". Main t=1 size=336 value=0 args=0x0 locals=0x98 0x0000 00000 (test.go:7) TEXT
    "". Main (SB), $152-0 0x0000 00000 (test.go:7) movq (TLS), CX 0x0009 00009 (test.go:7) LEAQ-24 (SP), AX    0x000e 00014 (test.go:7) CMPQ AX, (CX) 0x0012 00018 (test.go:7) JLS 0x0018 00024 (test.go:7)  Subq $152, SP 0x001f 00031 (test.go:7) Funcdata $, gclocals 7d2d5fca80364273fb07d5820a76fef4 (SB) 0x001f    00031 (Test.go:7) Funcdata $, gclocals 6e96661712a005168eba4ed6774db961 (SB) 0x001f 00031 (test.go:8) LEAQ Type. [1]int (SB), BX 0x0026 00038 (test.go:8) movq bx, (SP) 0x002a 00042 (test.go:8) PCDATA $, $0x002a 00042 (test.go:8) call Runtime.newobject (SB) 0x002f 00047 (Test.go:8) Movq 8 (SP), AX 0x0034 00052 (tes T.go:9) CMPQ AX, $0x0038 00056 (test.go:9) JEQ $, 313 0x003e 00062 (test.go:9) movq $ $, DX 0 x0045 00069 (test. Go:9) Movq $, CX
 

Notice that there is a call to NewObject. Where Test.go:8 shows that the memory of variable A is allocated on the heap!

In the Go FAQ there is an explanation:

How does I know whether a variable is allocated on the heap or the stack?

From a correctness standpoint, you don ' t need to know. Each variable in Go exists as long as there is references to it. The storage location chosen by the implementation are irrelevant to the semantics of the language.

The storage location does has an effect on writing efficient programs. When possible, the Go compilers would allocate variables that is local to a function in that function ' s stack frame. However, if the compiler cannot prove that the variable are not referenced after the function returns and then the compiler mu St allocate the variable on the garbage-collected heap to avoid dangling pointer errors. Also, if a local variable is very large, it might make more sense to store it on the heap rather than the stack.

In the current compilers, if a variable have its address taken, which variable is a candidate for allocation on the heap. However, a basic escape analysis recognizes some cases when such variables won't live past the return from the function And can reside on the stack.

It says that from the point of view of correctness, the user does not care where the memory is allocated. In general, if there is a place to use the address, then the variables will be allocated on the heap. For example, C cannot, but can do so in go:

Type struct T {xxx}
func f () *t {
    var ret t
    return &ret
}

Variable RET memory will be allocated on the heap, and go compiler will decide where to allocate memory (heap or stack) to ensure the correctness of the program.

The Go compiler is clever (smart), and it does escape analysis, and if it finds that the scope of the variable does not run too far, it can allocate space on the stack instead of the heap. For example, this code does not allocate memory on the heap, even if we allocate it with new.

Const Width, Height = 640, 480
type Cursor struct {
    X, Y int
}

func Center (c *cursor) {
    c.x + = Width/ 2
    c.y + = Height/2
}

func centercursor () {
    c: = new (Cursor)
    Center (c)
    FMT. Println (c.x, c.y)
}

Verify that:

Go tool compile-m test.go

test.go:17:can Inline Center
test.go:24:inlining call to Center
test.go:25:c. X escapes to heap
Test.go:25:c.y escapes to heap
test.go:23:centercursor new (Cursor) does not escape
test . go:25:centercursor ... argument does not escape
Test.go:17:center C does not escape

The parameter-M is the print out compilation optimization. From the output, it says that new (Cursor) does not have escape, so it is allocated on the stack. Equivalent to the C notation:

void Centercursor () {
    struct Cursor C;
    Center (&c);
}

Look at the other code, the difference from the beginning of the code, a use of FMT. Println, a Println of use.

Package Main

func main () {
    var a [1]int
    c: = a[:]
    println (c)
}

But!!! This code A is allocated on the stack. and the upper part of it is distributed on the heap.

On the one hand, go moves some of the things that appear to be allocated on the stack to the heap, and on the other hand, distributes the things that appear to be allocated on the heap on the stack. It is controlled by the run-out analysis from the compiler optimization.

This optimization is so bizarre that it is impossible to intuitively know what will be allocated on the heap and which will be allocated on the stack. Frankly speaking, I don't like this feature very much. Go self-assertion to get something behind what I can't be sure of. Incidentally, the other feature I don't like in Go is the init function.

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.