简体   繁体   中英

how to know golang allocated variable on the heap or the stack?

i read the golang FAQ: https://go.dev/doc/faq#stack_or_heap,i want to know when golang allocate variable on stack or heap. so i write code like below:

package main

import (
    "fmt"
)


type Object struct {
    Field int
}

func main() {
    A := Object{1}
    B := Object{2}
    fmt.Println(A,B)
    //fmt.Printf("A:%p;B:%p\n",&A,&B)
    //m := testStackOrHeap()
    //C:=m[A]
    //D:=m[B]
    //fmt.Printf("C:%p;D:%p\n",&C,&D)
}
//go:noinline
func testStackOrHeap() map[Object]Object {
    one:=1
    two:=2
    A := Object{one}
    B := Object{two}
    C:= Object{one}
    D := Object{two}
    fmt.Println(C,D)
    fmt.Printf("A:%p;B:%p\n",&A,&B)
    m := map[Object]Object{A: A, B: B}
    return m
}



then see how the compiler allocate the memory.the cmd is go tool compile "-m" main.go the output is below:

main.go:15:13: inlining call to fmt.Println
main.go:30:13: inlining call to fmt.Println
main.go:31:12: inlining call to fmt.Printf
main.go:15:13: A escapes to heap
main.go:15:13: B escapes to heap
main.go:15:13: []interface {} literal does not escape
main.go:26:2: moved to heap: A
main.go:27:2: moved to heap: B
main.go:30:13: C escapes to heap
main.go:30:13: D escapes to heap
main.go:30:13: []interface {} literal does not escape
main.go:31:12: []interface {} literal does not escape
main.go:32:24: map[Object]Object literal escapes to heap
<autogenerated>:1: .this does not escape

my question is: why not golang allocate variable AB in testStackOrHeap() to the stack,they can not escape to stackframe,if it allocate to heap, the gcworker need to collect it,but if it allocate in stack, it will release when function return.

As @Volker pointed out in a comment, the heap/stack distinction is an implementation detail, and the rules for escape analysis are defined by the compiler, not by the language. Correctness is the most important trait of a compiler, so a compiler's rules will frequently favor simplicity and performance over absolute "optimalness".

In this case, it's quite likely that the compiler doesn't know what fmt.Printf() will do with the pointers it receives. Therefore, it has to assume that the pointers might be stored somewhere on the heap by that function and that the references to those two objects might thus survive the call to testStackOrHeap() . Therefore, it errs on the side of caution and promotes those two variables to the heap.

(Note that your conclusion that they do not escape was presumably based on an assumption that fmt.Printf() won't store the pointers. Did you actually read the source code of that function to learn that it doesn't? If not, you can't actually be sure that it doesn't - just like the compiler isn't sure. And even if the current version of that function doesn't, future versions might.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM