Open
Description
Go version
go version go1.24.2 linux/amd64
Output of go env
in your module/workspace:
AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/home/tdakkota/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/tdakkota/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build509906469=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/tmp/example/go.mod'
GOMODCACHE='/home/tdakkota/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/tdakkota/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/home/tdakkota/.go'
GOSUMDB='sum.golang.org'
GOTELEMETRY='on'
GOTELEMETRYDIR='/home/tdakkota/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/home/tdakkota/.go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.24.2'
GOWORK=''
PKG_CONFIG='pkg-config'
What did you do?
https://go.dev/play/p/ug9pN6sRb5M
What did you see happen?
Parameters, result and #state1
leak to the heap.
$ go test -bench=. -benchmem
goos: linux
goarch: amd64
pkg: example.com/module
cpu: AMD Ryzen 9 5950X 16-Core Processor
BenchmarkRowContainsSeq-32 14006036 83.51 ns/op 72 B/op 4 allocs/op
PASS
ok example.com/module 1.173s
$ go test -gcflags='-m=1' -v ./
# example.com/module [example.com/module.test]
./m_test.go:14:2: can inline RowContainsSeq-range1
./m_test.go:23:2: skip inlining within testing.B.loop for for loop
./m_test.go:14:33: inlining call to strings.SplitSeq
./m_test.go:14:33: inlining call to strings.splitSeq
./m_test.go:14:33: inlining call to strings.explodeSeq
./m_test.go:23:12: inlining call to testing.(*B).Loop
./m_test.go:13:21: leaking param: haystack
./m_test.go:13:31: leaking param: needle
./m_test.go:14:6: r does not escape
/home/tdakkota/.go/src/strings/iter.go:37:14: yield does not escape
/home/tdakkota/.go/src/strings/iter.go:54:14: yield does not escape
./m_test.go:13:47: moved to heap: result
moved to heap: #next
./m_test.go:14:2: moved to heap: #state1
./m_test.go:14:2: func literal escapes to heap
./m_test.go:14:33: func literal does not escape
./m_test.go:14:33: func literal does not escape
./m_test.go:22:30: leaking param: b
...
tip (at f9ce1dd) is slightly better:
$ go version
go version devel go1.25-f9ce1dddc2 Sat Apr 26 08:01:54 2025 -0700 linux/amd64
$ go test -bench=. -benchmem
goos: linux
goarch: amd64
pkg: example.com/module
cpu: AMD Ryzen 9 5950X 16-Core Processor
BenchmarkRowContainsSeq-32 15135822 77.55 ns/op 72 B/op 3 allocs/op
PASS
ok example.com/module 1.177s
What did you expect to see?
No allocations at all.
Callback version (https://go.dev/play/p/IRc-1K3qP6M) of this code yields better results:
$ go test -bench=RowContainsCallback -benchmem
goos: linux
goarch: amd64
pkg: example.com/module
cpu: AMD Ryzen 9 5950X 16-Core Processor
BenchmarkRowContainsCallback-32 48458893 25.23 ns/op 0 B/op 0 allocs/op
PASS
ok example.com/module 1.225s