-
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: sync.Map keys will never be garbage collected #40999
Comments
Keys of sync.Map will never be deleted, this behaviour isn't the same as the native map. We should document this clearly. Fixes golang#40999 .
Keys of sync.Map will never be deleted, this behaviour isn't the same as the native map. We should document this clearly. Fixes golang#40999 .
This comment has been minimized.
This comment has been minimized.
Change https://golang.org/cl/250157 mentions this issue: |
I don’t think deleting a key from a map should leave the key. How are you determining that memory is leaking? |
@davecheney the current behaviour of sync.Map leaves the key. You can check it. |
Could you please explain how. |
@davecheney m.Delete only gets the value(e) from m.read or m.dirty, and e.delete() only sets it to nil.
|
@bcmills please excuse me if I got the attribution wrong, but is this the expected behaviour? |
@PureWhiteWu are you able to demonstrate a difference in runtime.Memstats to confirm that the key is not being deleted? |
@davecheney It's quite easy to obverse from pprof/heap. You can try it. |
@rsc Excuse me, is this behaviour by-design or a bug? |
Would you be able to include that data with your bug report please. |
@davecheney Is this enough? |
here, the linkBufferNode is referenced by something which is a key in a sync.Map that should have been deleted. |
Thank you for the frame graph, it’s hard to tell what is going on from that. I’m going to wait for the person who made that change to comment |
@davecheney I've added a Debug method in sync.Map:
And the example code to call Debug: https://play.golang.org/p/H3fkSdAw-JJ
As you can see, the keys are not deleted. |
@PureWhiteWu are you able to write a test that passes on 1.14 but fails on 1.15 |
@iand Sure, example code: https://play.golang.org/p/lHKYvukGbpZ
On go 1.14, output:
You can see that, if there's no read operation on map, the keys in |
@iand keys in |
Here is a simpler reproduction
|
This is not reproducible under Go 1.14
|
@davecheney Thank you for your reproduction! |
@PureWhiteWu would you consider abandoning your documentation CL. I do not believe we should document this incorrect behaviour. |
@davecheney maybe we should confirm if this is by-design or a bug first? |
This is clearly a change in behaviour between versions so it needs fixing |
git bisect points to 2e8dbae as @PureWhiteWu noted. |
@iand This is an undocumented behaviour, which is quite related to the implementation(on go 1.14 keys in |
And I think users should not know if a key is in |
@PureWhiteWu what reason would there be for chaining sync.Map in Go 1.15 so that Delete did not delete entries? I think the more reasonable answer is this is a bug. |
@davecheney |
If you add a sm.Range(...) between sm.Store and sm.Delete, the memory leaks on go 1.14, too. |
One bug at a time mate |
Change https://golang.org/cl/250197 mentions this issue: |
@gopherbot, please backport to 1.15. This is a regression from Go 1.14.7, and can cause difficult-to-predict memory leaks in existing code. |
Backport issue(s) opened: #41010 (for 1.14), #41011 (for 1.15). Remember to create the cherry-pick CL(s) as soon as the patch is submitted to master, according to https://golang.org/wiki/MinorReleases. |
Change https://golang.org/cl/250297 mentions this issue: |
Here's another problem: keys in the |
Keys in the But perhaps we are missing some sort of cache-miss tracking for deleted keys. If you have a real-world program for which that causes a problem, please open a new issue and we can at least see if there is a straightforward fix for it. (But also bear in mind that |
@bcmills thanks for your reply! |
This comment has been minimized.
This comment has been minimized.
Updates #40999 Fixes #41011 Change-Id: Ie32427e5cb5ed512b976b554850f50be156ce9f2 Reviewed-on: https://go-review.googlesource.com/c/go/+/250197 Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Bryan C. Mills <bcmills@google.com> (cherry picked from commit 94953d3) Reviewed-on: https://go-review.googlesource.com/c/go/+/250297 Run-TryBot: Bryan C. Mills <bcmills@google.com> Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
overdue fixing: golang/go#40999
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (
go env
)?Can reproduce on any os and arch.
What did you do?
We are using some big struct as keys for
sync.Map
, struct{} as value, and we observed a memory leak after upgrading to go 1.15. I confirmed that this is becausesync.Map
will never delete keys. Instead, it only set the value to nil.It worked well before 1.15 because we happened to have no read operation during the lifetime, and we were only reading it during shutdown so we didn't discover the memory leak, as some code like this: https://play.golang.org/p/YdY4gOcXVMO. So we happened to only have no key prompted to
sync.Map.read
, and thus Delete could delete the key insync.Map.dirty
.In go1.15, this behaviour was changed by https://go-review.googlesource.com/c/go/+/205899, and causes a memory leak in our code.
This isn't the same as the behaviour of the native map. I admit I have misused
sync.Map
, but I think this behaviour should either be documented clearly or be changed.The text was updated successfully, but these errors were encountered: