Live data from Hacker News

Go's escape analysis and why my function return worked

bonniesimon.in

11–20 of 76 posts

Re: Go's escape analysis and why my function return worked

#11
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.

Re: Go's escape analysis and why my function return worked

#12

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.

I like Go a lot, but I often wish we could be more explicit about where allocations are. It’s often important for writing performant code, but instead of having semantics we have to check against the stack analyzer which has poor ergonomics and may break at any time.

But yeah, to your point, returning a slice in a GC language is not some exotic thing.

Re: Go's escape analysis and why my function return worked

#13
post #3

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.

I am currently learning go and your comment made me sort some things out, but probably in a counterintuitive way.

Assuming to everything allocates on the heap, will solve this specific confusion.

My understanding is that C will let you crash quite fast if the stack becomes too large, go will dynamically grow the stack as needed. So it's possible to think you're working on the heap, but you are actually threshing the runtime with expensive stack grow calls. Go certainly tries to be smart about it with various strategies, but a rapid stack grow rate will have it's cost.

Re: Go's escape analysis and why my function return worked

#14

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.

I like Go a lot, but I often wish we could be more explicit about where allocations are. It’s often important for writing performant code, but instead of having semantics we have to check against the stack analyzer which has poor ergonomics and may break at any time. But yeah, to your point, returning a slice in a GC language is not some exotic thing.

Can you elaborate on the stack analyzer? All I could figure out was to see runtime.morestack calls that affected the runtime, but as far I remember the caller timings did exclude the cost. Having a clearer view of stack grow rates would be really great.

Re: Go's escape analysis and why my function return worked

#15
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)

Re: Go's escape analysis and why my function return worked

#16
post #15

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…

Interesting! This could be true. I'll play around with this in a bit.

Re: Go's escape analysis and why my function return worked

#17
post #15

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…

Interesting! This could be true. I'll play around with this in a bit.

Yeah I think what you're describing, returning a slice thus copying a reference to the same array (but not copying the array), then destroying the callee slice not causing the array to be freed, is just basic garbage collection logic, not escape analysis.

Re: Go's escape analysis and why my function return worked

#18
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.

Re: Go's escape analysis and why my function return worked

#19
post #15

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…

That’s the one.

Since 1.17 it’s not impossible for escape analysis to come into play for slices but afaik that is only a consideration for slices with a statically known size under 64KiB.

Re: Go's escape analysis and why my function return worked

#20
post #18

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.

Go has been my primary language for a few years now, and I’ve had to do extra work to make sure I’m avoiding the heap maybe five times. Stack and heap aren’t on my mind most of the time when designing and writing Go, even though I have a pretty good understanding of how it works. The same applies to the garbage collector. It just doesn’t matter most of the time.

That said, when it matters it matters a lot. In those times I wish it was more visible in Go code, but I would want it to not get in the way the rest of the time. But I’m ok with the status quo of hunting down my notes on escape analysis every few months and taking a few minutes to get reacquainted.

Side note: I love how you used “from above” and “from below”. It makes me feel angelic as somebody who came from above; even if Java and Ruby hardly seemed like heaven.

Post reply on HN