5 ms·
Its worth calling out that abstractions can kill you in unexpected ways with go. Anytime you use an interface it forces a heap allocation, even if the object i
by liquidgecka 2y ago
Its worth calling out that abstractions can kill you in unexpected ways with go.
Anytime you use an interface it forces a heap allocation, even if the object is only used read only and within the same scope. That includes calls to things like fmt.Printf() so doing a for loop that prints the value of i forces the integer backing i to be heap allocated, along with every other value that you printed. So if you helpfully make every api in your library use an interface you are forcing the callers to use heap allocations for every single operation.
- slashdev 2y agoI thought surely an integer could be inlined into the interface, I thought Go used to do that. But I tried it on the playground, and it heap allocates it: https://go.dev/play/p/zHfnQfJ9OGc https://go.dev/play/p/zHfnQfJ9OGc
- masklinn 2y agoGo did use to do that, it was removed years ago, in 1.4: https://go.dev/doc/go1.4#runtime https://go.dev/doc/go1.4#runtime
- kbolino 2y agoBasically, anything that isn't a thin pointer (*T, chan, map) gets boxed nowadays. The end result is that both words of an interface value are always pointers [1], which is very friendly to the garbage collector (setting aside the extra allocations when escape analysis fails). I've seen some tricks in the standard library to avoid boxing, e.g. how strings and times are handled by log/slog [2]. [1]: https://github.com/teh-cmc/go-internals/blob/master/chapter2_interfaces/README.md#overview-of-the-datastructures https://github.com/teh-cmc/go-internals/blob/master/chapter2... [2]: https://cs.opensource.google/go/go/+/refs/tags/go1.24.1:src/log/slog/value.go;l=21 https://cs.opensource.google/go/go/+/refs/tags/go1.24.1:src/...
- deleted 2y ago[deleted]
- ncruces 2y agoslog.Value looks incredibly useful. Just imagine a day where database/sql doesn't generate a tonne of garbage because it moves to use something like that?
- ominous_prime 2y agogo1.15 re-added small integer packing into interfaces: https://go.dev/doc/go1.15#runtime https://go.dev/doc/go1.15#runtime
- masklinn 2y agoIt didn't, actually. Instead go 1.15 has a static array of the first 256 positive integers, and when it needs to box one for an interface it gets a pointer into that array instead: https://go-review.googlesource.com/c/go/+/216401/4/src/runtime/iface.go https://go-review.googlesource.com/c/go/+/216401/4/src/runti... This array is also used for single-byte strings (which previously had its own array): https://go-review.googlesource.com/c/go/+/221979/3/src/runtime/string.go https://go-review.googlesource.com/c/go/+/221979/3/src/runti...
- ominous_prime 2y agoIt didn't, do what? I would consider the first 256 integers to be "small integers" ;) > Converting a small integer value into an interface value no longer causes allocation I forgot that it can also be used for single byte strings, That's not an optimization I ever encountered being useful, but it's there!
- masklinn 2y ago> It didn't, do what? Reintroduce “packing into interfaces”. It did a completely different thing. Small integers remain not inlined.