because when you only access an int that is passed by value in the function it knows it can’t escape.
if you pass the string/value than the the variable can escape, and since the value could point back to the struct itself, it can escape, meaning the entire struct needs to be on the heap. > On Aug 30, 2024, at 3:43 AM, rkerno <rik.kernag...@projectcatalysts.com> > wrote: > > Hi Everyone, > > https://gist.github.com/rkerno/c875609bdeb2459582609da36b54bf72 > <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 golang-nuts+unsubscr...@googlegroups.com > <mailto:golang-nuts+unsubscr...@googlegroups.com>. > To view this discussion on the web visit > https://groups.google.com/d/msgid/golang-nuts/3ff0270c-caf0-4a23-9cdf-08bf40e83a33n%40googlegroups.com > > <https://groups.google.com/d/msgid/golang-nuts/3ff0270c-caf0-4a23-9cdf-08bf40e83a33n%40googlegroups.com?utm_medium=email&utm_source=footer>. -- 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 golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/96E4ACF6-BCA3-4A87-91E8-EC80B6237EBA%40ix.netcom.com.