-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
sync: map.Range has started allocating as of Go 1.20 #62404
Comments
CC @bcmills |
Seems like this allocation comes from the change from atomic.Value to atomic.Pointer in this CL https://go-review.googlesource.com/c/go/+/426074 |
CC @dsnet |
Specifically, what is allocating memory is the empty value for the return: func (m *Map) loadReadOnly() readOnly {
if p := m.read.Load(); p != nil {
return *p
}
return readOnly{}
} |
Ah, probably escape analysis. What we need here is some manual memory management. 🙃 The line in m.read.Store(&read) should be changed to instead make a copy of the variable, and store a pointer to that copy so that it only escapes in that one code path. (I guess the compiler doesn't do live-range splitting for local variables.) |
After the change from CL 426074 the Range method on Map always escape the read variable, generating an allocation. Since the compiler doesn't do live-range splitting for local variables we need to use some hints to only escape in that particular branch. Fixes golang#62404
Change https://go.dev/cl/524976 mentions this issue: |
After the change from CL 426074 the Range method on Map always escape the read variable, generating an allocation. Since the compiler doesn't do live-range splitting for local variables we need to use some hints to only escape in that particular branch. Fixes golang#62404
After the change from CL 426074 the Range method on Map always escape the read variable, generating an allocation. Since the compiler doesn't do live-range splitting for local variables we need to use some hints to only escape in that particular branch. Fixes golang#62404
Change https://go.dev/cl/525235 mentions this issue: |
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes (with go 1.21.0)
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
The latest versions of go runtime added a 16Byte allocation to sync map Range function. This was not the case in prior releases.
I have tested go 1.19.5 (which does not do the allocation) and go 1.20.4 and go 1.21.0 (both of which do the allocation).
What did you expect to see?
[murthy@testbuild] 12:35:32 $ /usr/local/go1.19.5/bin/go test -bench Range goos: linux goarch: amd64 pkg: smap/go1195 cpu: AMD EPYC 7352 24-Core Processor BenchmarkRange-16 840378 1418 ns/op 0 B/op 0 allocs/op PASS ok smap/go1195 2.041s [murthy@testbuild] 12:35:39 $
What did you see instead?
[murthy@testbuild] 12:36:03 $ go version go version go1.20.4 linux/amd64 [murthy@testbuild] 12:36:05 $ go test -bench Range goos: linux goarch: amd64 pkg: smap/go1204 cpu: AMD EPYC 7352 24-Core Processor BenchmarkRange-16 782552 1512 ns/op 16 B/op 1 allocs/op PASS ok smap/go1204 2.029s [murthy@testbuild] 12:36:12 $
The text was updated successfully, but these errors were encountered: