diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index ebd4c33bda..255bba2868 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -332,10 +332,11 @@ func (c *gcControllerState) startCycle() { // error response). if memstats.next_gc <= heapminimum { memstats.heap_marked = uint64(float64(memstats.next_gc) / (1 + c.triggerRatio)) + memstats.heap_reachable = memstats.heap_marked } // Compute the heap goal for this cycle - c.heapGoal = memstats.heap_marked + memstats.heap_marked*uint64(gcpercent)/100 + c.heapGoal = memstats.heap_reachable + memstats.heap_reachable*uint64(gcpercent)/100 // Compute the total mark utilization goal and divide it among // dedicated and fractional workers. @@ -1117,11 +1118,21 @@ func gcMark(start_time int64) { cachestats() - // Trigger the next GC cycle when the allocated heap has - // grown by triggerRatio over the marked heap size. + // Compute the reachable heap size at the beginning of the + // cycle. This is approximately the marked heap size at the + // end (which we know) minus the amount of marked heap that + // was allocated after marking began (which we don't know, but + // is approximately the amount of heap that was allocated + // since marking began). + memstats.heap_reachable = work.bytesMarked - (memstats.heap_live - gcController.initialHeapLive) + + // Trigger the next GC cycle when the allocated heap has grown + // by triggerRatio over the reachable heap size. Assume that + // we're in steady state, so the reachable heap size is the + // same now as it was at the beginning of the GC cycle. memstats.heap_live = work.bytesMarked memstats.heap_marked = work.bytesMarked - memstats.next_gc = uint64(float64(memstats.heap_live) * (1 + gcController.triggerRatio)) + memstats.next_gc = uint64(float64(memstats.heap_reachable) * (1 + gcController.triggerRatio)) if memstats.next_gc < heapminimum { memstats.next_gc = heapminimum } diff --git a/src/runtime/mstats.go b/src/runtime/mstats.go index 36931fb6b4..3711c397cc 100644 --- a/src/runtime/mstats.go +++ b/src/runtime/mstats.go @@ -74,6 +74,10 @@ type mstats struct { // unlike heap_live, heap_marked does not change until the // next mark termination. heap_marked uint64 + + // heap_reachable is an estimate of the reachable heap bytes + // at the end of the previous GC. + heap_reachable uint64 } var memstats mstats