Go version:
$ go version
go version go1.8.1 darwin/amd64
Issue
Say we have this code:
package main
type Fooer interface {
Foo()
}
// HandleFooer is intended to show that passing interface will not rasie an allocation.
func HandleFooer(f Fooer) {
// Passing interface Fooer<*Concrete> will not raise an allocation
// even if we do some work on f, such as f.(*Concrete).Foo().
}
type Concrete byte
func (c Concrete) Foo() {}
And if we run these benchmarks (with -gcflags="-l"):
package main
import "testing"
func BenchmarkCallFooer(b *testing.B) {
for i := 0; i < b.N; i++ {
var c Concrete = 42// Moved to heap.
Fooer(&c).Foo()
}
}
func BenchmarkPassFooer(b *testing.B) {
for i := 0; i < b.N; i++ {
var c Concrete = 42 // Not moved to heap.
HandleFooer(Fooer(&c))
}
}
The output is:
BenchmarkCallFooer-4 100000000 17.6 ns/op 1 B/op 1 allocs/op
BenchmarkPassFooer-4 500000000 2.99 ns/op 0 B/op 0 allocs/op
With -gcflags="-m -m":
./iface_test.go:17: HandleFooer f does not escape
./iface_test.go:22: Fooer(&c) escapes to heap
./iface_test.go:22: from Fooer(&c).Foo() (receiver in indirect call) at ./iface_test.go:22
./iface_test.go:22: &c escapes to heap
./iface_test.go:22: from Fooer(&c) (interface-converted) at ./iface_test.go:22
./iface_test.go:22: from Fooer(&c).Foo() (receiver in indirect call) at ./iface_test.go:22
./iface_test.go:21: moved to heap: c
Expected behavior: &c stays on stack in both cases.
Go version:
Issue
Say we have this code:
And if we run these benchmarks (with
-gcflags="-l"):The output is:
With
-gcflags="-m -m":Expected behavior:
&cstays on stack in both cases.