runtime: why the buf size of the member mspancache in P is 128, just only use half in allocMSpanLocked()

// allocMSpanLocked allocates an mspan object.
//
// h.lock must be held.
//
// allocMSpanLocked must be called on the system stack because
// its caller holds the heap lock. See mheap for details.
// Running on the system stack also ensures that we won't
// switch Ps during this function. See tryAllocMSpan for details.
//
//go:systemstack
func (h *mheap) allocMSpanLocked() *mspan {
	assertLockHeld(&h.lock)

	pp := getg().m.p.ptr()
	if pp == nil {
		// We don't have a p so just do the normal thing.
		return (*mspan)(h.spanalloc.alloc())
	}
	// Refill the cache if necessary.
	if pp.mspancache.len == 0 {
		const refillCount = len(pp.mspancache.buf) / 2
		for i := 0; i < refillCount; i++ {
			pp.mspancache.buf[i] = (*mspan)(h.spanalloc.alloc())
		}
		pp.mspancache.len = refillCount
	}
	// Pull off the last entry in the cache.
	s := pp.mspancache.buf[pp.mspancache.len-1]
	pp.mspancache.len--
	return s
}

$ go version
go version go1.16.4 linux/amd64

Why the value of refillCount just only has half of pp.mspancache.buf ?

Looks like the code snippet is from here.

Ian Lance Taylor provided an answer in this golang-nuts thread.

As a reference for other readers:

Because the freeMSpanLocked method will add the MSpan being freed to
the cache if possible. If the cache is full, then freeMSpanLocked has
to release it to the general pool, for some future call to
allocMSpanLocked. It’s better for the cache to be neither entirely
full nor entirely empty. Setting it to half full is a compromise.

Ian

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.