aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/mgcsweep.go
diff options
context:
space:
mode:
authorMichael Anthony Knyszek <mknyszek@google.com>2019-11-19 17:32:17 +0000
committerMichael Knyszek <mknyszek@google.com>2020-04-30 18:12:03 +0000
commit2491c5fd2451783e4ba6630345805de1e7761e3b (patch)
treeef09e22883f9255205149eba2515c7fb60e5d09a /src/runtime/mgcsweep.go
parentc7915376ce3cdd172bf71ca4127c67f196b8e43e (diff)
downloadgo-2491c5fd2451783e4ba6630345805de1e7761e3b.tar.gz
go-2491c5fd2451783e4ba6630345805de1e7761e3b.zip
runtime: wake scavenger and update address on sweep done
This change modifies the semantics of waking the scavenger: rather than wake on any update to pacing, wake when we know we will have work to do, that is, when the sweeper is done. The current scavenger runs over the address space just once per GC cycle, and we want to maximize the chance that the scavenger observes the most attractive scavengable memory in that pass (i.e. free memory with the highest address), so the timing is important. By having the scavenger awaken and reset its search space when the sweeper is done, we increase the chance that the scavenger will observe the most attractive scavengable memory, because no more memory will be freed that GC cycle (so the highest scavengable address should now be available). Furthermore, in applications that go idle, this means the background scavenger will be awoken even if another GC doesn't happen, which isn't true today. However, we're unable to wake the scavenger directly from within the sweeper; waking the scavenger involves modifying timers and readying goroutines, the latter of which may trigger an allocation today (and the sweeper may run during allocation!). Instead, we do the following: 1. Set a flag which is checked by sysmon. sysmon will clear the flag and wake the scavenger. 2. Wake the scavenger unconditionally at sweep termination. The idea behind this policy is that it gets us close enough to the state above without having to deal with the complexity of waking the scavenger in deep parts of the runtime. If the application goes idle and sweeping finishes (so we don't reach sweep termination), then sysmon will wake the scavenger. sysmon has a worst-case 20 ms delay in responding to this signal, which is probably fine if the application is completely idle anyway, but if the application is actively allocating, then the proportional sweeper should help ensure that sweeping ends very close to sweep termination, so sweep termination is a perfectly reasonable time to wake up the scavenger. Updates #35788. Change-Id: I84289b37816a7d595d803c72a71b7f5c59d47e6b Reviewed-on: https://go-review.googlesource.com/c/go/+/207998 Run-TryBot: Michael Knyszek <mknyszek@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Austin Clements <austin@google.com>
Diffstat (limited to 'src/runtime/mgcsweep.go')
-rw-r--r--src/runtime/mgcsweep.go26
1 files changed, 26 insertions, 0 deletions
diff --git a/src/runtime/mgcsweep.go b/src/runtime/mgcsweep.go
index f99a6cc122..2f3bf1d1e9 100644
--- a/src/runtime/mgcsweep.go
+++ b/src/runtime/mgcsweep.go
@@ -145,6 +145,11 @@ func finishsweep_m() {
}
}
+ // Sweeping is done, so if the scavenger isn't already awake,
+ // wake it up. There's definitely work for it to do at this
+ // point.
+ wakeScavenger()
+
nextMarkBitArenaEpoch()
}
@@ -241,6 +246,27 @@ func sweepone() uintptr {
// Decrement the number of active sweepers and if this is the
// last one print trace information.
if atomic.Xadd(&mheap_.sweepers, -1) == 0 && atomic.Load(&mheap_.sweepdone) != 0 {
+ // Since the sweeper is done, reset the scavenger's pointer
+ // into the heap and wake it if necessary.
+ //
+ // The scavenger is signaled by the last sweeper because once
+ // sweeping is done, we will definitely have useful work for
+ // the scavenger to do, since the scavenger only runs over the
+ // heap once per GC cyle. This update is not done during sweep
+ // termination because in some cases there may be a long delay
+ // between sweep done and sweep termination (e.g. not enough
+ // allocations to trigger a GC) which would be nice to fill in
+ // with scavenging work.
+ systemstack(func() {
+ lock(&mheap_.lock)
+ mheap_.pages.resetScavengeAddr()
+ unlock(&mheap_.lock)
+ })
+ // Since we might sweep in an allocation path, it's not possible
+ // for us to wake the scavenger directly via wakeScavenger, since
+ // it could allocate. Ask sysmon to do it for us instead.
+ readyForScavenger()
+
if debug.gcpacertrace > 0 {
print("pacer: sweep done at heap size ", memstats.heap_live>>20, "MB; allocated ", (memstats.heap_live-mheap_.sweepHeapLiveBasis)>>20, "MB during sweep; swept ", mheap_.pagesSwept, " pages at ", sweepRatio, " pages/byte\n")
}