diff options
-rw-r--r-- | src/runtime/mgcsweep.go | 64 |
1 files changed, 36 insertions, 28 deletions
diff --git a/src/runtime/mgcsweep.go b/src/runtime/mgcsweep.go index 910257a26d..acad55e777 100644 --- a/src/runtime/mgcsweep.go +++ b/src/runtime/mgcsweep.go @@ -170,12 +170,12 @@ func mSpan_Sweep(s *mspan, preserve bool) bool { cl := s.sizeclass size := s.elemsize res := false - nfree := 0 + nfree := 0 // Set to -1 for large span var head, end gclinkptr c := _g_.m.mcache - sweepgenset := false + freeToHeap := false // Mark any free objects in this span so we don't collect them. sstart := uintptr(s.start << _PageShift) @@ -237,31 +237,10 @@ func mSpan_Sweep(s *mspan, preserve bool) bool { // important to set sweepgen before returning it to heap atomicstore(&s.sweepgen, sweepgen) - sweepgenset = true - - // NOTE(rsc,dvyukov): The original implementation of efence - // in CL 22060046 used SysFree instead of SysFault, so that - // the operating system would eventually give the memory - // back to us again, so that an efence program could run - // longer without running out of memory. Unfortunately, - // calling SysFree here without any kind of adjustment of the - // heap data structures means that when the memory does - // come back to us, we have the wrong metadata for it, either in - // the MSpan structures or in the garbage collection bitmap. - // Using SysFault here means that the program will run out of - // memory fairly quickly in efence mode, but at least it won't - // have mysterious crashes due to confused memory reuse. - // It should be possible to switch back to SysFree if we also - // implement and then call some kind of MHeap_DeleteSpan. - if debug.efence > 0 { - s.limit = 0 // prevent mlookup from finding this span - sysFault(unsafe.Pointer(p), size) - } else { - mHeap_Free(&mheap_, s, 1) - } - c.local_nlargefree++ - c.local_largefree += size - res = true + + // Free the span after heapBitsSweepSpan + // returns, since it's not done with the span. + freeToHeap = true } else { // Free small object. if size > 2*ptrSize { @@ -285,7 +264,10 @@ func mSpan_Sweep(s *mspan, preserve bool) bool { // But we need to set it before we make the span available for allocation // (return it to heap or mcentral), because allocation code assumes that a // span is already swept if available for allocation. - if !sweepgenset && nfree == 0 { + // + // TODO(austin): Clean this up by consolidating atomicstore in + // large span path above with this. + if !freeToHeap && nfree == 0 { // The span must be in our exclusive ownership until we update sweepgen, // check for potential races. if s.state != mSpanInUse || s.sweepgen != sweepgen-1 { @@ -298,6 +280,32 @@ func mSpan_Sweep(s *mspan, preserve bool) bool { c.local_nsmallfree[cl] += uintptr(nfree) res = mCentral_FreeSpan(&mheap_.central[cl].mcentral, s, int32(nfree), head, end, preserve) // MCentral_FreeSpan updates sweepgen + } else if freeToHeap { + // Free large span to heap + + // NOTE(rsc,dvyukov): The original implementation of efence + // in CL 22060046 used SysFree instead of SysFault, so that + // the operating system would eventually give the memory + // back to us again, so that an efence program could run + // longer without running out of memory. Unfortunately, + // calling SysFree here without any kind of adjustment of the + // heap data structures means that when the memory does + // come back to us, we have the wrong metadata for it, either in + // the MSpan structures or in the garbage collection bitmap. + // Using SysFault here means that the program will run out of + // memory fairly quickly in efence mode, but at least it won't + // have mysterious crashes due to confused memory reuse. + // It should be possible to switch back to SysFree if we also + // implement and then call some kind of MHeap_DeleteSpan. + if debug.efence > 0 { + s.limit = 0 // prevent mlookup from finding this span + sysFault(unsafe.Pointer(uintptr(s.start<<_PageShift)), size) + } else { + mHeap_Free(&mheap_, s, 1) + } + c.local_nlargefree++ + c.local_largefree += size + res = true } if trace.enabled { traceGCSweepDone() |