Skip to content

proposal: runtime: GC pacer redesign #44167

Closed
@mknyszek

Description

@mknyszek
Contributor

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

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

gopherbot commented on Feb 8, 2021

@gopherbot
Contributor

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

mknyszek

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

storozhukBM

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.

mknyszek

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

added a commit that references this issue on Feb 16, 2021
gopherbot

gopherbot commented on Feb 16, 2021

@gopherbot
Contributor

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

gopherbot

gopherbot commented on Feb 18, 2021

@gopherbot
Contributor

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

gopherbot

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

62 remaining items

Loading
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

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @mknyszek@dmitshur@storozhukBM@gopherbot

        Issue actions

          proposal: runtime: GC pacer redesign · Issue #44167 · golang/go