aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/malloc.go2
-rw-r--r--src/runtime/mgc.go49
2 files changed, 38 insertions, 13 deletions
diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go
index 44479cc2be..ec2e547d3f 100644
--- a/src/runtime/malloc.go
+++ b/src/runtime/malloc.go
@@ -117,8 +117,6 @@ const (
pageShift = _PageShift
pageSize = _PageSize
- concurrentSweep = _ConcurrentSweep
-
_PageSize = 1 << _PageShift
_PageMask = _PageSize - 1
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go
index de5ae0ae00..8efee74243 100644
--- a/src/runtime/mgc.go
+++ b/src/runtime/mgc.go
@@ -135,9 +135,12 @@ import (
)
const (
- _DebugGC = 0
- _ConcurrentSweep = true
- _FinBlockSize = 4 * 1024
+ _DebugGC = 0
+ _FinBlockSize = 4 * 1024
+
+ // concurrentSweep is a debug flag. Disabling this flag
+ // ensures all spans are swept while the world is stopped.
+ concurrentSweep = true
// debugScanConservative enables debug logging for stack
// frames that are scanned conservatively.
@@ -969,6 +972,7 @@ func gcMarkTermination() {
// before continuing.
})
+ var stwSwept bool
systemstack(func() {
work.heap2 = work.bytesMarked
if debug.gccheckmark > 0 {
@@ -987,7 +991,7 @@ func gcMarkTermination() {
// marking is complete so we can turn the write barrier off
setGCPhase(_GCoff)
- gcSweep(work.mode)
+ stwSwept = gcSweep(work.mode)
})
mp.traceback = 0
@@ -1079,9 +1083,19 @@ func gcMarkTermination() {
// Those aren't tracked in any sweep lists, so we need to
// count them against sweep completion until we ensure all
// those spans have been forced out.
+ //
+ // If gcSweep fully swept the heap (for example if the sweep
+ // is not concurrent due to a GODEBUG setting), then we expect
+ // the sweepLocker to be invalid, since sweeping is done.
+ //
+ // N.B. Below we might duplicate some work from gcSweep; this is
+ // fine as all that work is idempotent within a GC cycle, and
+ // we're still holding worldsema so a new cycle can't start.
sl := sweep.active.begin()
- if !sl.valid {
+ if !stwSwept && !sl.valid {
throw("failed to set sweep barrier")
+ } else if stwSwept && sl.valid {
+ throw("non-concurrent sweep failed to drain all sweep queues")
}
systemstack(func() { startTheWorldWithSema() })
@@ -1123,9 +1137,15 @@ func gcMarkTermination() {
pp.pinnerCache = nil
})
})
- // Now that we've swept stale spans in mcaches, they don't
- // count against unswept spans.
- sweep.active.end(sl)
+ if sl.valid {
+ // Now that we've swept stale spans in mcaches, they don't
+ // count against unswept spans.
+ //
+ // Note: this sweepLocker may not be valid if sweeping had
+ // already completed during the STW. See the corresponding
+ // begin() call that produced sl.
+ sweep.active.end(sl)
+ }
// Print gctrace before dropping worldsema. As soon as we drop
// worldsema another cycle could start and smash the stats
@@ -1538,10 +1558,12 @@ func gcMark(startTime int64) {
// gcSweep must be called on the system stack because it acquires the heap
// lock. See mheap for details.
//
+// Returns true if the heap was fully swept by this function.
+//
// The world must be stopped.
//
//go:systemstack
-func gcSweep(mode gcMode) {
+func gcSweep(mode gcMode) bool {
assertWorldStopped()
if gcphase != _GCoff {
@@ -1559,12 +1581,16 @@ func gcSweep(mode gcMode) {
sweep.centralIndex.clear()
- if !_ConcurrentSweep || mode == gcForceBlockMode {
+ if !concurrentSweep || mode == gcForceBlockMode {
// Special case synchronous sweep.
// Record that no proportional sweeping has to happen.
lock(&mheap_.lock)
mheap_.sweepPagesPerByte = 0
unlock(&mheap_.lock)
+ // Flush all mcaches.
+ for _, pp := range allp {
+ pp.mcache.prepareForSweep()
+ }
// Sweep all spans eagerly.
for sweepone() != ^uintptr(0) {
sweep.npausesweep++
@@ -1578,7 +1604,7 @@ func gcSweep(mode gcMode) {
// available immediately.
mProf_NextCycle()
mProf_Flush()
- return
+ return true
}
// Background sweep.
@@ -1588,6 +1614,7 @@ func gcSweep(mode gcMode) {
ready(sweep.g, 0, true)
}
unlock(&sweep.lock)
+ return false
}
// gcResetMarkState resets global state prior to marking (concurrent