logoalt Hacker News

Go's escape analysis and why my function return worked

34 pointsby bonniesimon12/05/202534 commentsview on HN

Comments

mwshermanlast Thursday at 3:22 PM

Shameless plug, if one wishes to track down allocations in Go, an allocations explorer for VS Code: https://marketplace.visualstudio.com/items?itemName=Clipperh...

show 1 reply
tdfirthlast Thursday at 1:53 PM

I don’t think this is confusing to the vast majority of people writing Go.

In my experience, the average programmer isn’t even aware of the stack vs heap distinction these days. If you learned to write code in something like Python then coming at Go from “above” this will just work the way you expect.

If you come at Go from “below” then yeah it’s a bit weird.

show 3 replies
jstanleylast Thursday at 11:50 AM

It's not confusing that this works in Go. (In my opinion).

A straightforward reading of the code suggests that it should do what it does.

The confusion here is a property of C, not of Go. It's a property of C that you need to care about the difference between the stack and the heap, it's not a general fact about programming. I don't think Go is doing anything confusing.

show 1 reply
foldr12/05/2025

This seems to be a persistent source of confusion. Escape analysis is just an optimization. You don't need to think about it to understand why your Go code behaves the way it does. Just imagine that everything is allocated on the heap and you won't have any surprises.

show 3 replies
nasretdinovlast Thursday at 9:50 AM

If the functions get inlined (which they might if they're small enough), then the code won't even need to allocate on heap! That's a kind of optimisation that's not really possible without transparent escape analysis.

matthewaveryusalast Thursday at 2:53 PM

Nope, this analysis is wrong. Decompile your code and look at what's going on: https://godbolt.org/z/f1nx9ffYK

The thing being returned is a slice (a fat pointer) that has pointer, length, capacity. In the code linked you'll see the fat pointer being returned from the function as values. in C you'd get just AX (the pointer, without length and cap)

    command-line-arguments_readLogsFromPartition_pc122:
            MOVQ    BX, AX     // slice.ptr   -> AX (first result register)
            MOVQ    SI, BX     // slice.len   -> BX (second)
            MOVQ    DX, CX     // slice.cap   -> CX (third)
The gargabe collection is happening in the FUNCDATA/PCDATA annotations, but I don't really know how that works.
knorkerlast Thursday at 1:40 PM

Are you sure this is what's happening? Looks to me like the slice object is returned by value, and the array was always on the heap. See https://go.dev/play/p/Bez0BgRny7G (the address of the slice object changed, so it's not the same object on the heap)

Sure, Go has escape analysis, but is that really what's happening here?

Isn't this a better example of escape analysis: https://go.dev/play/p/qX4aWnnwQV2 (the object retains its address, always on the heap, in both caller and callee)

show 4 replies
potato-peelerlast Thursday at 11:12 AM

If the variable was defined in the calling function itself, and a pointer was passed, I guess the variable will still be in the heap?

show 1 reply
samdoesnothinglast Thursday at 10:44 AM

Go is returning a copy of the slice, in the same way that C would return a copy of an int or struct if you returned it. The danger of C behaviour in this instance is that a stack allocated array decays into a pointer which points to the deallocated memory. Otherwise the behaviour is pretty similar between the languages.

show 1 reply
gethlylast Thursday at 2:40 PM

> In C, you can't assign a value in a local function and then return it

I am so glad I never taken up C. This sound like a nightmare of a DX to me.

show 1 reply