package runtime
import (
+ "internal/goexperiment"
"runtime/internal/atomic"
"unsafe"
)
g *g
parked bool
- nbgsweep uint32
- npausesweep uint32
-
// active tracks outstanding sweepers and the sweep
// termination condition.
active activeSweep
// instantly. If GC was forced before the concurrent sweep
// finished, there may be spans to sweep.
for sweepone() != ^uintptr(0) {
- sweep.npausesweep++
}
// Make sure there aren't any outstanding sweepers left.
lock(&sweep.lock)
sweep.parked = true
c <- 1
- goparkunlock(&sweep.lock, waitReasonGCSweepWait, traceEvGoBlock, 1)
+ goparkunlock(&sweep.lock, waitReasonGCSweepWait, traceBlockGCSweep, 1)
for {
// bgsweep attempts to be a "low priority" goroutine by intentionally
const sweepBatchSize = 10
nSwept := 0
for sweepone() != ^uintptr(0) {
- sweep.nbgsweep++
nSwept++
if nSwept%sweepBatchSize == 0 {
goschedIfBusy()
continue
}
sweep.parked = true
- goparkunlock(&sweep.lock, waitReasonGCSweepWait, traceEvGoBlock, 1)
+ goparkunlock(&sweep.lock, waitReasonGCSweepWait, traceBlockGCSweep, 1)
}
}
if debug.scavtrace > 0 {
systemstack(func() {
lock(&mheap_.lock)
- released := atomic.Loaduintptr(&mheap_.pages.scav.released)
- printScavTrace(released, false)
- atomic.Storeuintptr(&mheap_.pages.scav.released, 0)
+
+ // Get released stats.
+ releasedBg := mheap_.pages.scav.releasedBg.Load()
+ releasedEager := mheap_.pages.scav.releasedEager.Load()
+
+ // Print the line.
+ printScavTrace(releasedBg, releasedEager, false)
+
+ // Update the stats.
+ mheap_.pages.scav.releasedBg.Add(-releasedBg)
+ mheap_.pages.scav.releasedEager.Add(-releasedEager)
unlock(&mheap_.lock)
})
}
throw("mspan.sweep: bad span state")
}
- if trace.enabled {
- traceGCSweepSpan(s.npages * _PageSize)
+ trace := traceAcquire()
+ if trace.ok() {
+ trace.GCSweepSpan(s.npages * _PageSize)
+ traceRelease(trace)
}
mheap_.pagesSwept.Add(int64(s.npages))
// efficient; allocfreetrace has massive overhead.
mbits := s.markBitsForBase()
abits := s.allocBitsForIndex(0)
- for i := uintptr(0); i < s.nelems; i++ {
- if !mbits.isMarked() && (abits.index < s.freeindex || abits.isMarked()) {
+ for i := uintptr(0); i < uintptr(s.nelems); i++ {
+ if !mbits.isMarked() && (abits.index < uintptr(s.freeindex) || abits.isMarked()) {
x := s.base() + i*s.elemsize
if debug.allocfreetrace != 0 {
tracefree(unsafe.Pointer(x), size)
//
// Check the first bitmap byte, where we have to be
// careful with freeindex.
- obj := s.freeindex
+ obj := uintptr(s.freeindex)
if (*s.gcmarkBits.bytep(obj / 8)&^*s.allocBits.bytep(obj / 8))>>(obj%8) != 0 {
s.reportZombies()
}
// Check remaining bytes.
- for i := obj/8 + 1; i < divRoundUp(s.nelems, 8); i++ {
+ for i := obj/8 + 1; i < divRoundUp(uintptr(s.nelems), 8); i++ {
if *s.gcmarkBits.bytep(i)&^*s.allocBits.bytep(i) != 0 {
s.reportZombies()
}
s.allocCount = nalloc
s.freeindex = 0 // reset allocation index to start of span.
s.freeIndexForScan = 0
- if trace.enabled {
- getg().m.p.ptr().traceReclaimed += uintptr(nfreed) * s.elemsize
+ if traceEnabled() {
+ getg().m.p.ptr().trace.reclaimed += uintptr(nfreed) * s.elemsize
}
// gcmarkBits becomes the allocBits.
// get a fresh cleared gcmarkBits in preparation for next GC
s.allocBits = s.gcmarkBits
- s.gcmarkBits = newMarkBits(s.nelems)
+ s.gcmarkBits = newMarkBits(uintptr(s.nelems))
+
+ // refresh pinnerBits if they exists
+ if s.pinnerBits != nil {
+ s.refreshPinnerBits()
+ }
// Initialize alloc bits cache.
s.refillAllocCache(0)
return true
}
// Return span back to the right mcentral list.
- if uintptr(nalloc) == s.nelems {
+ if nalloc == s.nelems {
mheap_.central[spc].mcentral.fullSwept(sweepgen).push(s)
} else {
mheap_.central[spc].mcentral.partialSwept(sweepgen).push(s)
} else {
mheap_.freeSpan(s)
}
+ if goexperiment.AllocHeaders && s.largeType != nil && s.largeType.Kind_&kindGCProg != 0 {
+ // In the allocheaders experiment, the unrolled GCProg bitmap is allocated separately.
+ // Free the space for the unrolled bitmap.
+ systemstack(func() {
+ s := spanOf(uintptr(unsafe.Pointer(s.largeType)))
+ mheap_.freeManual(s, spanAllocPtrScalarBits)
+ })
+ s.largeType = nil
+ }
// Count the free in the consistent, external stats.
stats := memstats.heapStats.acquire()
print("runtime: marked free object in span ", s, ", elemsize=", s.elemsize, " freeindex=", s.freeindex, " (bad use of unsafe.Pointer? try -d=checkptr)\n")
mbits := s.markBitsForBase()
abits := s.allocBitsForIndex(0)
- for i := uintptr(0); i < s.nelems; i++ {
+ for i := uintptr(0); i < uintptr(s.nelems); i++ {
addr := s.base() + i*s.elemsize
print(hex(addr))
- alloc := i < s.freeindex || abits.isMarked()
+ alloc := i < uintptr(s.freeindex) || abits.isMarked()
if alloc {
print(" alloc")
} else {
return
}
- if trace.enabled {
- traceGCSweepStart()
+ trace := traceAcquire()
+ if trace.ok() {
+ trace.GCSweepStart()
+ traceRelease(trace)
}
// Fix debt if necessary.
}
}
- if trace.enabled {
- traceGCSweepDone()
+ trace = traceAcquire()
+ if trace.ok() {
+ trace.GCSweepDone()
+ traceRelease(trace)
}
}