Skip to content

proposal: runtime: GC pacer redesign #44167

Closed

Description

@mknyszek

GC Pacer Redesign

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:

  1. Including all non-heap sources of GC work (stacks, globals) in pacing decisions.
  2. Reframing the pacing problem as a search problem, "solved" by a proportional-integral controller,
  3. 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.

Full design

Found here.

Activity

  1. added this to the Go1.17 milestone on Feb 8, 2021
  2. self-assigned this
    on Feb 8, 2021
  3. gopherbot commented on Feb 8, 2021

    @gopherbot
    Contributor

    Change https://golang.org/cl/290489 mentions this issue: design: add GC pacer redesign

  4. mknyszek commented on Feb 8, 2021

    @mknyszek
    ContributorAuthor

    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

  5. storozhukBM commented on Feb 12, 2021

    @storozhukBM

    @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.

  6. mknyszek commented on Feb 13, 2021

    @mknyszek
    ContributorAuthor

    @storozhukBM forcegcperiod 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).

  7. added a commit that references this issue on Feb 16, 2021
  8. gopherbot commented on Feb 16, 2021

    @gopherbot
    Contributor

    Change https://golang.org/cl/292789 mentions this issue: design: add user-configurable memory target

  9. gopherbot commented on Feb 18, 2021

    @gopherbot
    Contributor

    Change https://golang.org/cl/293790 mentions this issue: design: regenerate graphs for GC pacer redesign

  10. gopherbot commented on Feb 23, 2021

    @gopherbot
    Contributor

    Change https://golang.org/cl/295509 mentions this issue: design: add initial conditions section to GC pacer redesign

  11. gopherbot commented on Apr 1, 2021

    @gopherbot
    Contributor

    Change https://golang.org/cl/306605 mentions this issue: runtime: make gcEffectiveGrowthRatio a method on gcControllerState

  12. 39 remaining items

  13. added
    NeedsFixThe path to resolution is known, but the work has not been done.
    on Nov 10, 2021
  14. gopherbot commented on Dec 1, 2021

    @gopherbot
    Contributor

    Change https://golang.org/cl/368137 mentions this issue: runtime: switch back to a 4 MiB min heap for GOEXPERIMENT=pacerredesign

  15. gopherbot commented on Apr 10, 2022

    @gopherbot
    Contributor

    Change https://go.dev/cl/399300 mentions this issue: runtime: update description of GODEBUG=gctrace=1

  16. moved this to Accepted in Proposalson Aug 10, 2022
  17. removed this from Proposalson Nov 16, 2022
  18. locked and limited conversation to collaborators on Jun 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions