The following Go program reports that the function makes an allocation to do the string to []byte conversion, even though the compiler reports the conversion as non-escaping.
https://play.golang.org/p/y2d2RiYqK5
It prints:
48 B/op 1 allocs/op
Given that the compiler has marked it as non-escaping, I'd expect no allocations.
go version devel +eab99a8 Mon Jun 26 21:12:22 2017 +0000 linux/amd64
Comment From: randall77
It's non-escaping, but its size is unknown. We need to allocate []byte of unknown size on the heap.
Comment From: bcmills
We shouldn't even need to do that if the slice isn't mutated, right? (How hard would it be to make the escape analysis also do mutability?)
Comment From: rogpeppe
For the record I encountered this issue when passing a string to hex.Decode. Mutability analysis would be amazing, but just avoiding the allocation would be nice.
Comment From: bradfitz
Dup of #2205 ?
Comment From: rogpeppe
Although the particular example would be fixed if #2205 was fixed, I don't think it's quite the same issue. I hadn't realised that all variable-length allocations escaped (strictly speaking that's not true, because []byte(string) where len(string)<=32 is stack-allocated), and I'm not sure that others do either.
I'm probably not the only one who was using -gcflags -m output as a proxy for whether there's an allocation or not. Given that we're (I presume) not about to make some kind of instant-free arena for variable-length items, perhaps another way of addressing this issue might be to change the output printed by the -m flag to make it clearer that this the result of this kind of operation may actually escape to the heap.
Comment From: robpike
Sure, it's escaped to the heap but that's as far as it will get. The guard towers that surround the heap are well-manned and your memory will never get outside the heap's walls. You can relax.
Comment From: andybons
@rogpeppe is your proposal to change the output of the -m flag to make this clearer? Is this worthy of a proposal or NeedsDecision? Trying to figure out next steps.
Comment From: bradfitz
Unplanned, needs fix, performance.
No decision needed. This is just work, and somewhat tricky work.
Comment From: andybons
Thanks, Brad. Updated.
Comment From: josharian
Given that we're (I presume) not about to make some kind of instant-free arena for variable-length items
Cross-reference: https://github.com/golang/go/issues/20533
Comment From: philjb
Should this ticket remain open now that https://github.com/golang/go/issues/2205 is resolved? The original demonstration code reports zero allocations now (as expected with 2205 fix).
Comment From: randall77
Yes, I think this is fixed.
Comment From: thepudds
I will briefly add that @rogpeppe in https://github.com/golang/go/issues/20881#issuecomment-312567987 seems to have said he thought #2205 was not exactly the same as this issue here:
Although the particular example would be fixed if https://github.com/golang/go/issues/2205 was fixed, I don't think it's quite the same issue.
If I followed, it seems part of the concern might have been whether it's clear what is happening from the -gcflags=-m
logs.
FWIW, I think there is a reasonably clear log emitted with the -gcflags=-m
flag for the new-ish zero-copy conversion for this example (thanks to the work done in #2205), though that's based on a quick look and maybe I missed something:
t.go:23:14: zero-copy string->[]byte conversion
t.go:22:13: s does not escape
t.go:23:14: ([]byte)(s) does not escape
In any event, there might be opportunities to improve the logging, but that might now be better tracked elsewhere (and/or maybe with a different example than the one at the top of this issue).