aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/runtime/mgcsweep.go64
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()