-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Avoid unnecessary map allocation when writing progress #4116
Conversation
`MultiWriter` would create an unnecessary map allocation when the `Write` method was used. The `Write` method would create a progress object with the meta field initialized to the meta field of the writer itself. It then invoked its own `WriteRawProgress` method which would see two maps with the metadata and erroneously believe that they were different and needed to be merged into a single metadata map. Since this map is initialized with the metadata of the writer before `WriteRawProgress` is invoked, this merge was unnecessary and could add a lot of unnecessary memory allocations during a build. This changes the `MultiWriter.Write` method to invoke the private `writeRawProgress` which performs the actual write and avoids the metadata merge. Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
763ed22
to
4c83fcf
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good find, but I'm not sure if this is actually related to #3655 . Do you have any measurements to support that? This reduces allocations but I don't see it fixing a memory leak.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In WriteRawProgress
, if len(p.meta) == 0
we still make a clone of ps.meta
. I wonder if that is intentional or not.
@tonistiigi I don't think #3655 is a memory leak and it doesn't seem the original issue referred to it as one. I took a look at the linked issues and I suspect they're unrelated. I think the problem is The profile they had pointed to this set of calls as being the result of allocations and the profile also showed these as
The other potentially problematic line is in
So I think that means the only potential memory allocation is the map allocation. I am a bit concerned that I didn't see any memory allocations from the It seems like we initialize the buildkit/util/progress/multiwriter.go Line 66 in 4c83fcf
So Line 376 in 8ffc03b
Which pretty much guarantees that My first thought was to improve the merging logic so if But yea you're right that we're missing the case where As an aside, I've also found that many times Go is not the best at doing garbage collections fast enough to avoid the Linux OOM killer. I've had scenarios where we used a lot of memory for small objects, the memory wasn't considered "in-use" and should have been collected, but Go was too slow to free the memory and Linux killed the process with OOM even though there was memory theoretically available. Which might explain some of the issues related to the OOM killer. |
MultiWriter
would create an unnecessary map allocation when theWrite
method was used. TheWrite
method would create a progressobject with the meta field initialized to the meta field of the writer
itself. It then invoked its own
WriteRawProgress
method which wouldsee two maps with the metadata and erroneously believe that they were
different and needed to be merged into a single metadata map.
Since this map is initialized with the metadata of the writer before
WriteRawProgress
is invoked, this merge was unnecessary and could adda lot of unnecessary memory allocations during a build.
This changes the
MultiWriter.Write
method to invoke the privatewriteRawProgress
which performs the actual write and avoids themetadata merge.
Fixes #3655.