]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: recheck GC trigger before actually starting GC
authorAustin Clements <austin@google.com>
Fri, 31 Jul 2015 17:52:17 +0000 (13:52 -0400)
committerAustin Clements <austin@google.com>
Tue, 4 Aug 2015 18:54:32 +0000 (18:54 +0000)
Currently allocation checks the GC trigger speculatively during
allocation and then triggers the GC without rechecking. As a result,
it's possible for G 1 and G 2 to detect the trigger simultaneously,
both enter startGC, G 1 actually starts GC while G 2 gets preempted
until after the whole GC cycle, then G 2 immediately starts another GC
cycle even though the heap is now well under the trigger.

Fix this by re-checking the GC trigger non-speculatively just before
actually kicking off a new GC cycle.

This contributes to #11911 because when this happens, we definitely
don't finish the background sweep before starting the next GC cycle,
which can significantly delay the start of concurrent scan.

Change-Id: I560ab79ba5684ba435084410a9765d28f5745976
Reviewed-on: https://go-review.googlesource.com/13025
Reviewed-by: Russ Cox <rsc@golang.org>
Reviewed-by: Rick Hudson <rlh@golang.org>
src/runtime/mgc.go

index f0e05f61aaa6df8f1362162ff084890b4a766af7..de9f4f51fdabb6bb3f58e4ffb25605cf6c461f0e 100644 (file)
@@ -841,6 +841,14 @@ func startGC(mode int) {
        // trigger concurrent GC
        readied := false
        lock(&bggc.lock)
+       // The trigger was originally checked speculatively, so
+       // recheck that this really should trigger GC. (For example,
+       // we may have gone through a whole GC cycle since the
+       // speculative check.)
+       if !shouldtriggergc() {
+               unlock(&bggc.lock)
+               return
+       }
        if !bggc.started {
                bggc.working = 1
                bggc.started = true