You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Author: Michael Knyszek (with lots of input from Austin Clements, David Chase, and Jeremy Faller)
Abstract
Go's tracing garbage collector runs concurrently with the application, and thus requires an algorithm to determine when to start a new cycle. In the runtime, this algorithm is referred to as the pacer. Until now, the garbage collector has framed this process as an optimization problem, utilizing a proportional controller to achieve a desired stopping-point (that is, the cycle completes just as the heap reaches a certain size) as well as a desired CPU utilization. While this approach has served Go well for a long time, the design has accrued many corner cases due to resolved issues, as well as a backlog of unresolved issues.
I propose redesigning the garbage collector's pacer from the ground up to capture the things it does well and eliminate the problems that have been discovered.
More specifically, I propose:
Including all non-heap sources of GC work (stacks, globals) in pacing decisions.
Reframing the pacing problem as a search problem, "solved" by a proportional-integral controller,
Extending the hard heap goal to the worst-case heap goal of the next GC,
(1) will resolve long-standing issues with small heap sizes, allowing the Go garbage collector to scale down and act more predictably in general.
(2) will eliminate offset error present in the current design, will allow turning off mark-assist almost entirely outside of exceptional cases, improving allocation latency, and will enable clearer designs for setting memory limits on Go applications.
(3) will enable smooth and consistent response to large changes in the live heap size with large GOGC values.
By the way: this design feels solid to me, but has not gone through any rounds of feedback yet. In the interest of transparency, I'm hoping to get feedback and work on this here on GitHub going forward.
So, given that, I would not be surprised if there are errors in the document. Please take a look when you have a chance!
Do I understand correctly that the forcegcperiod is required because the current pacer does not consider non-heap sources of GC work? Is it necessary to call GC periodically in application with effectively zero heap allocation rate to collects stacks, etc.? If I understood your proposal correctly, it seems like it should be possible to remove these periodic calls of GC, and applications that don't create new goroutines and don't allocate anything on heap should never trigger garbage collections, which is a good benefit by itself.
@storozhukBMforcegcperiod is pretty much completely separate from this proposal. Not accounting for non-heap sources of work more directly affects the minimum heap size and whether the GC reaches its goals. Related though is #44163, which is partly motivated by some of the ill effects of the forcegcperiod trigger.
I believe forcegcperiod exists these days to help finalizers run in long-running mostly-idle programs. For example, if you have an external resource tied to the finalizer, you want that cleaned up eventually (and sooner, probably). Going by the API it need not ever run. But, then we could just turn the forced GC on only if there's active finalizers or something, so I'm not convinced that's the only reason. Shrinking stacks periodically also might be a reason, but that seems less critical.
Anyway, I have to look into this again so don't quote me. My memory is hazy. :) I'll dig into the reasons why next week (I don't see them documented anywhere).
Activity
gopherbot commentedon Feb 8, 2021
Change https://golang.org/cl/290489 mentions this issue:
design: add GC pacer redesignmknyszek commentedon Feb 8, 2021
By the way: this design feels solid to me, but has not gone through any rounds of feedback yet. In the interest of transparency, I'm hoping to get feedback and work on this here on GitHub going forward.
So, given that, I would not be surprised if there are errors in the document. Please take a look when you have a chance!
CC @randall77 @jeremyfaller @dr2chase @aclements
storozhukBM commentedon Feb 12, 2021
@mknyszek
Do I understand correctly that the forcegcperiod is required because the current pacer does not consider non-heap sources of GC work? Is it necessary to call GC periodically in application with effectively zero heap allocation rate to collects stacks, etc.? If I understood your proposal correctly, it seems like it should be possible to remove these periodic calls of GC, and applications that don't create new goroutines and don't allocate anything on heap should never trigger garbage collections, which is a good benefit by itself.
mknyszek commentedon Feb 13, 2021
@storozhukBM
forcegcperiodis pretty much completely separate from this proposal. Not accounting for non-heap sources of work more directly affects the minimum heap size and whether the GC reaches its goals. Related though is #44163, which is partly motivated by some of the ill effects of theforcegcperiodtrigger.I believe
forcegcperiodexists these days to help finalizers run in long-running mostly-idle programs. For example, if you have an external resource tied to the finalizer, you want that cleaned up eventually (and sooner, probably). Going by the API it need not ever run. But, then we could just turn the forced GC on only if there's active finalizers or something, so I'm not convinced that's the only reason. Shrinking stacks periodically also might be a reason, but that seems less critical.Anyway, I have to look into this again so don't quote me. My memory is hazy. :) I'll dig into the reasons why next week (I don't see them documented anywhere).
design: add GC pacer redesign
gopherbot commentedon Feb 16, 2021
Change https://golang.org/cl/292789 mentions this issue:
design: add user-configurable memory targetgopherbot commentedon Feb 18, 2021
Change https://golang.org/cl/293790 mentions this issue:
design: regenerate graphs for GC pacer redesigndesign: regenerate graphs for GC pacer redesign
gopherbot commentedon Feb 23, 2021
Change https://golang.org/cl/295509 mentions this issue:
design: add initial conditions section to GC pacer redesigndesign: add initial conditions section to GC pacer redesign
gopherbot commentedon Apr 1, 2021
Change https://golang.org/cl/306605 mentions this issue:
runtime: make gcEffectiveGrowthRatio a method on gcControllerState39 remaining items
runtime: add testing framework and basic tests for GC pacer
runtime: implement GC pacer redesign
gopherbot commentedon Dec 1, 2021
Change https://golang.org/cl/368137 mentions this issue:
runtime: switch back to a 4 MiB min heap for GOEXPERIMENT=pacerredesignruntime: break out new minimum heap size into a goexperiment
design: update gc-pacer-redesign and remove inaccuracies
gopherbot commentedon Apr 10, 2022
Change https://go.dev/cl/399300 mentions this issue:
runtime: update description of GODEBUG=gctrace=1runtime: update description of GODEBUG=gctrace=1