21

In Go, it seems there are no constructors, but it is suggested that you allocate an object of a struct type using a function, usually named by "New" + TypeName, for example

func NewRect(x,y, width, height float) *Rect {
     return &Rect(x,y,width, height)
}

However, I am not sure about the memory layout of Go. In C/C++, this kind of code means you return a pointer, which point to a temporary object because the variable is allocated on the stack, and the variable may be some trash after the function return. In Go, do I have to worry such kind of thing? Because It seems no standard shows that what kind of data will be allocated on the stack vs what kind of data will be allocated on the heap.

As in Java, there seems to have a specific point out that the basic type such as int, float will be allocated on the stack, other object derived from the object will be allocated on the heap. In Go, is there a specific talk about this?

Dave C
  • 7,729
  • 4
  • 49
  • 65
python
  • 1,870
  • 4
  • 24
  • 35
  • 7
    It will be allocated on the heap. The Go compiler can detect when an object will live outside the stack, and automatically allocates it on the heap. You can see it if you compile with `go build -gcflags '-m'` to see the optimization decisions. – siritinga Sep 04 '14 at 06:59
  • 2
    @python: Your intuition was right that you don't have to worry about it. In practice it's true that it will be allocated on the heap, but Go's memory model is very simple, and you actually don't have to think about stacks and heaps at all. You can just think about variables. If you take the address of something, Go will guarantee that that address is always valid so long as you have a pointer to it. It shouldn't matter to you as a programmer how that happens. (although, obviously, it can be interesting to think about how it's implemented, and there's some cool stuff going on there too) – joshlf Sep 04 '14 at 07:41
  • thanks for all of your guys answer – python Sep 04 '14 at 07:44
  • @synful "If you take the address of something, Go will guarantee that that address is always valid so long as you have a pointer to it"... well except for a pointer to some composite literal, like `x := &((2 * 3) + 4)`: http://stackoverflow.com/a/25601963/6309 – VonC Sep 04 '14 at 07:45
  • Yes, but Go won't blindly let you do that and have a runtime error - it won't let you compile it. – joshlf Sep 04 '14 at 14:09

1 Answers1

32

The Composite Literal section mentions:

Taking the address of a composite literal (§Address operators) generates a unique pointer to an instance of the literal's value.

That means the pointer returned by the New function will be a valid one (allocated on the stack).
Calls:

In a function call, the function value and arguments are evaluated in the usual order.
After they are evaluated, the parameters of the call are passed by value to the function and the called function begins execution.
The return parameters of the function are passed by value back to the calling function when the function returns.

You can see more in this answer and this thread.

As mentioned in "Stack vs heap allocation of structs in Go, and how they relate to garbage collection":

It's worth noting that the words "stack" and "heap" do not appear anywhere in the language spec.


The blog post "Escape Analysis in Go" details what happens, mentioning the FAQ:

When possible, the Go compilers will allocate variables that are local to a function in that function's stack frame.
However, if the compiler cannot prove that the variable is not referenced after the function returns, then the compiler must 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.

The blog post adds:

The code that does the “escape analysis” lives in src/cmd/gc/esc.c.
Conceptually, it tries to determine if a local variable escapes the current scope; the only two cases where this happens are when a variable’s address is returned, and when its address is assigned to a variable in an outer scope.
If a variable escapes, it has to be allocated on the heap; otherwise, it’s safe to put it on the stack.

Interestingly, this applies to new(T) allocations as well.
If they don’t escape, they’ll end up being allocated on the stack. Here’s an example to clarify matters:

var intPointerGlobal *int = nil

func Foo() *int {
    anInt0 := 0
    anInt1 := new(int)

    anInt2 := 42
    intPointerGlobal = &anInt2

    anInt3 := 5

    return &anInt3
}

Above, anInt0 and anInt1 do not escape, so they are allocated on the stack;
anInt2 and anInt3 escape, and are allocated on the heap.


See also "Five things that make Go fast":

Unlike C, which forces you to choose if a value will be stored on the heap, via malloc, or on the stack, by declaring it inside the scope of the function, Go implements an optimisation called escape analysis.

Go’s optimisations are always enabled by default.
You can see the compiler’s escape analysis and inlining decisions with the -gcflags=-m switch.

Because escape analysis is performed at compile time, not run time, stack allocation will always be faster than heap allocation, no matter how efficient your garbage collector is.

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 1
    Even if the spec doesn't mention it, the compiler does in its escape analysis: `./test.go:11: new(int) escapes to heap` – siritinga Sep 04 '14 at 07:07
  • @siritinga Indeed. I have edited the answer with more details on escape analysis, coming from http://stackoverflow.com/questions/13715237/return-pointer-to-local-struct#comment23436456_13715281 – VonC Sep 04 '14 at 07:13
  • it was just a comment. At the end it is not so easy to avoid using heap/stack terms :) – siritinga Sep 04 '14 at 07:14
  • 1
    @siritinga yes, but http://dave.cheney.net/2014/06/07/five-things-that-make-go-fast shows that goroutine stacks are quite different from the normal stack (very small, no guard page, ...) – VonC Sep 04 '14 at 07:18
  • 2
    @VonC note to self, that was my 1000th Nice Answer. – VonC Apr 29 '15 at 09:30