if unsafe.Sizeof(workbuf{}) != _WorkbufSize {
throw("size of Workbuf is suboptimal")
}
+ gcController.heapMinimum = defaultHeapMinimum
// No sweep on the first cycle.
mheap_.sweepDrained = 1
// Fake a heapMarked value so it looks like a trigger at
// heapMinimum is the appropriate growth from heapMarked.
// This will go into computing the initial GC goal.
- gcController.heapMarked = uint64(float64(heapMinimum) / (1 + gcController.triggerRatio))
+ gcController.heapMarked = uint64(float64(gcController.heapMinimum) / (1 + gcController.triggerRatio))
// Set gcPercent from the environment. This will also compute
// and set the GC trigger and goal.
// own write.
return gcController.heapLive >= gcController.trigger
case gcTriggerTime:
- if gcPercent < 0 {
+ if gcController.gcPercent < 0 {
return false
}
lastgc := int64(atomic.Load64(&memstats.last_gc_nanotime))
defaultHeapMinimum = 4 << 20
)
-var (
- // heapMinimum is the minimum heap size at which to trigger GC.
- // For small heaps, this overrides the usual GOGC*live set rule.
- //
- // When there is a very small live set but a lot of allocation, simply
- // collecting when the heap reaches GOGC*live results in many GC
- // cycles and high total per-GC overhead. This minimum amortizes this
- // per-GC overhead while keeping the heap reasonably small.
- //
- // During initialization this is set to 4MB*GOGC/100. In the case of
- // GOGC==0, this will set heapMinimum to 0, resulting in constant
- // collection even when the heap size is small, which is useful for
- // debugging.
- heapMinimum uint64 = defaultHeapMinimum
-
- // Initialized from $GOGC. GOGC=off means no GC.
- gcPercent int32
-)
-
func init() {
if offset := unsafe.Offsetof(gcController.heapLive); offset%8 != 0 {
println(offset)
var gcController gcControllerState
type gcControllerState struct {
+ // Initialized from $GOGC. GOGC=off means no GC.
+ gcPercent int32
+
+ _ uint32 // padding so following 64-bit values are 8-byte aligned
+
+ // heapMinimum is the minimum heap size at which to trigger GC.
+ // For small heaps, this overrides the usual GOGC*live set rule.
+ //
+ // When there is a very small live set but a lot of allocation, simply
+ // collecting when the heap reaches GOGC*live results in many GC
+ // cycles and high total per-GC overhead. This minimum amortizes this
+ // per-GC overhead while keeping the heap reasonably small.
+ //
+ // During initialization this is set to 4MB*GOGC/100. In the case of
+ // GOGC==0, this will set heapMinimum to 0, resulting in constant
+ // collection even when the heap size is small, which is useful for
+ // debugging.
+ heapMinimum uint64
+
// triggerRatio is the heap growth ratio that triggers marking.
//
// E.g., if this is 0.6, then GC should start when the live
// is when assists are enabled and the necessary statistics are
// available).
func (c *gcControllerState) revise() {
- gcPercent := gcPercent
+ gcPercent := c.gcPercent
if gcPercent < 0 {
// If GC is disabled but we're running a forced GC,
// act like GOGC is huge for the below calculations.
// has grown by GOGC/100 over the heap marked by the last
// cycle.
goal := ^uint64(0)
- if gcPercent >= 0 {
- goal = c.heapMarked + c.heapMarked*uint64(gcPercent)/100
+ if c.gcPercent >= 0 {
+ goal = c.heapMarked + c.heapMarked*uint64(c.gcPercent)/100
}
// Set the trigger ratio, capped to reasonable bounds.
- if gcPercent >= 0 {
- scalingFactor := float64(gcPercent) / 100
+ if c.gcPercent >= 0 {
+ scalingFactor := float64(c.gcPercent) / 100
// Ensure there's always a little margin so that the
// mutator assist ratio isn't infinity.
maxTriggerRatio := 0.95 * scalingFactor
// We trigger the next GC cycle when the allocated heap has
// grown by the trigger ratio over the marked heap size.
trigger := ^uint64(0)
- if gcPercent >= 0 {
+ if c.gcPercent >= 0 {
trigger = uint64(float64(c.heapMarked) * (1 + triggerRatio))
// Don't trigger below the minimum heap size.
- minTrigger := heapMinimum
+ minTrigger := c.heapMinimum
if !isSweepDone() {
// Concurrent sweep happens in the heap growth
// from gcController.heapLive to trigger, so ensure
// Run on the system stack since we grab the heap lock.
systemstack(func() {
lock(&mheap_.lock)
- out = gcPercent
+ out = gcController.gcPercent
if in < 0 {
in = -1
}
- gcPercent = in
- heapMinimum = defaultHeapMinimum * uint64(gcPercent) / 100
+ gcController.gcPercent = in
+ gcController.heapMinimum = defaultHeapMinimum * uint64(gcController.gcPercent) / 100
// Update pacing in response to gcPercent change.
gcController.commit(gcController.triggerRatio)
unlock(&mheap_.lock)