// Small objects are allocated from the per-P cache's free lists.
// Large objects (> 32 kB) are allocated straight from the heap.
func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
+ if gcphase == _GCmarktermination {
+ throw("mallocgc called with gcphase == _GCmarktermination")
+ }
shouldhelpgc := false
if size == 0 {
return unsafe.Pointer(&zerobase)
systemstack(stoptheworld)
systemstack(finishsweep_m) // finish sweep before we start concurrent scan.
+ // clearpools before we start the GC. If we wait they memory will not be
+ // reclaimed until the next GC cycle.
+ clearpools()
if mode == gcBackgroundMode { // Do as much work concurrently as possible
systemstack(func() {
// Begin mark termination.
gctimer.cycle.markterm = nanotime()
stoptheworld()
- gcphase = _GCoff
+ // The gcphase is _GCmark, it will transition to _GCmarktermination
+ // below. The important thing is that the wb remains active until
+ // all marking is complete. This includes writes made by the GC.
})
} else {
// For non-concurrent GC (mode != gcBackgroundMode)
gcResetGState()
}
+ // World is stopped.
+ // Start marktermination which includes enabling the write barrier.
+ gcphase = _GCmarktermination
+
startTime := nanotime()
if mp != acquirem() {
throw("gcwork: rescheduled")
}
- // TODO(rsc): Should the concurrent GC clear pools earlier?
- clearpools()
-
_g_ := getg()
_g_.m.traceback = 2
gp := _g_.m.curg
gcMark(startTime)
clearCheckmarks()
}
+
+ // marking is complete so we can turn the write barrier off
+ gcphase = _GCoff
gcSweep(mode)
if debug.gctrace > 1 {
// Reset these so that all stacks will be rescanned.
gcResetGState()
finishsweep_m()
+
+ // Still in STW but gcphase is _GCoff, reset to _GCmarktermination
+ // At this point all objects will be found during the gcMark which
+ // does a complete STW mark and object scan.
+ gcphase = _GCmarktermination
gcMark(startTime)
+ gcphase = _GCoff // marking is done, turn off wb.
gcSweep(mode)
}
})
}
}
+ if gcphase != _GCoff {
+ throw("gc done but gcphase != _GCoff")
+ }
+
systemstack(starttheworld)
releasem(mp)
tracegc()
}
+ if gcphase != _GCmarktermination {
+ throw("in gcMark expecting to see gcphase as _GCmarktermination")
+ }
t0 := start_time
work.tstart = start_time
- gcphase = _GCmarktermination
-
var t1 int64
if debug.gctrace > 0 {
t1 = nanotime()
}
- gcCopySpans()
+ gcCopySpans() // TODO(rlh): should this be hoisted and done only once? Right now it is done for normal marking and also for checkmarking.
work.nwait = 0
work.ndone = 0
throw("work.partial != 0")
}
- gcphase = _GCoff
var t3 int64
if debug.gctrace > 0 {
t3 = nanotime()
}
func gcSweep(mode int) {
+ if gcphase != _GCoff {
+ throw("gcSweep being done but phase is not GCoff")
+ }
gcCopySpans()
lock(&mheap_.lock)