Hi Everyone,
https://gist.github.com/rkerno/c875609bdeb2459582609da36b54bf72
I'm struggling to wrap my head around the root cause of this issue.
Accessing certain fields of a struct triggers go to allocate the complete
struct on the heap. The key ingredients are:
- A struct with a contained slice of structs defined inline
- Calls to functions via a function pointer
What follows is a contrived example to demonstrate / investigate the
problem.
const (
//
// When requireZeroAllocations == true...
//
// BenchmarkAllocations-2 27763290 52.28 ns/op
0 B/op 0 allocs/op
//
// When requireZeroAllocations == false...
//
// BenchmarkAllocations-2 14403922 1532.00 ns/op
2304 B/op 2 allocs/op
//
requireZeroAllocations = false
)
type (
X struct {
id uint
key string
value any
children []X
useId useIdFunc
useX useXFunc
useKey useKeyFunc
useValue useValueFunc
unused [128]uint64 // Demonstrates that the whole struct is placed on the
heap!
}
useIdFunc = func(id uint)
useXFunc = func(key string, value any)
useKeyFunc = func(key string)
useValueFunc = func(value any)
)
func scanX(x X) {
if len(x.children) > 0 {
for i := 0; i < len(x.children); i++ {
scanX(x.children[i])
}
return
}
x.useId(x.id)
if !requireZeroAllocations {
// Why can we access the id field without an allocation, but as soon as we
access
// the string or any fields the entire struct is placed on the heap?
x.useKey(x.key)
x.useX(x.key, x.value)
x.useValue(x.value)
}
}
func printId(id uint) {
}
func printX(key string, value any) {
}
func printKey(key string) {
}
func printValue(value any) {
}
The benchmark used to demonstrate the behaviour is:
func BenchmarkAllocations(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
scanX(
X{
id: 0,
key: "root",
value: nil,
children: []X{
{
id: 1,
key: "level1",
value: nil,
children: []X{
{
id: 2,
key: "k1",
value: "v1",
children: nil,
useId: printId,
useX: printX,
useKey: printKey,
useValue: printValue,
},
},
},
},
},
)
}
})
}
Any insights or ideas why go exhibits this behaviour would be appreciated.
Cheers,
Rik
--
You received this message because you are subscribed to the Google Groups
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/golang-nuts/3ff0270c-caf0-4a23-9cdf-08bf40e83a33n%40googlegroups.com.