1// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package runtime
6
7import (
8	"internal/runtime/atomic"
9	"runtime/internal/sys"
10	"unsafe"
11)
12
13// Per-thread (in Go, per-P) cache for small objects.
14// This includes a small object cache and local allocation stats.
15// No locking needed because it is per-thread (per-P).
16//
17// mcaches are allocated from non-GC'd memory, so any heap pointers
18// must be specially handled.
19type mcache struct {
20	_ sys.NotInHeap
21
22	// The following members are accessed on every malloc,
23	// so they are grouped here for better caching.
24	nextSample uintptr // trigger heap sample after allocating this many bytes
25	scanAlloc  uintptr // bytes of scannable heap allocated
26
27	// Allocator cache for tiny objects w/o pointers.
28	// See "Tiny allocator" comment in malloc.go.
29
30	// tiny points to the beginning of the current tiny block, or
31	// nil if there is no current tiny block.
32	//
33	// tiny is a heap pointer. Since mcache is in non-GC'd memory,
34	// we handle it by clearing it in releaseAll during mark
35	// termination.
36	//
37	// tinyAllocs is the number of tiny allocations performed
38	// by the P that owns this mcache.
39	tiny       uintptr
40	tinyoffset uintptr
41	tinyAllocs uintptr
42
43	// The rest is not accessed on every malloc.
44
45	alloc [numSpanClasses]*mspan // spans to allocate from, indexed by spanClass
46
47	stackcache [_NumStackOrders]stackfreelist
48
49	// flushGen indicates the sweepgen during which this mcache
50	// was last flushed. If flushGen != mheap_.sweepgen, the spans
51	// in this mcache are stale and need to the flushed so they
52	// can be swept. This is done in acquirep.
53	flushGen atomic.Uint32
54}
55
56// A gclink is a node in a linked list of blocks, like mlink,
57// but it is opaque to the garbage collector.
58// The GC does not trace the pointers during collection,
59// and the compiler does not emit write barriers for assignments
60// of gclinkptr values. Code should store references to gclinks
61// as gclinkptr, not as *gclink.
62type gclink struct {
63	next gclinkptr
64}
65
66// A gclinkptr is a pointer to a gclink, but it is opaque
67// to the garbage collector.
68type gclinkptr uintptr
69
70// ptr returns the *gclink form of p.
71// The result should be used for accessing fields, not stored
72// in other data structures.
73func (p gclinkptr) ptr() *gclink {
74	return (*gclink)(unsafe.Pointer(p))
75}
76
77type stackfreelist struct {
78	list gclinkptr // linked list of free stacks
79	size uintptr   // total size of stacks in list
80}
81
82// dummy mspan that contains no free objects.
83var emptymspan mspan
84
85func allocmcache() *mcache {
86	var c *mcache
87	systemstack(func() {
88		lock(&mheap_.lock)
89		c = (*mcache)(mheap_.cachealloc.alloc())
90		c.flushGen.Store(mheap_.sweepgen)
91		unlock(&mheap_.lock)
92	})
93	for i := range c.alloc {
94		c.alloc[i] = &emptymspan
95	}
96	c.nextSample = nextSample()
97	return c
98}
99
100// freemcache releases resources associated with this
101// mcache and puts the object onto a free list.
102//
103// In some cases there is no way to simply release
104// resources, such as statistics, so donate them to
105// a different mcache (the recipient).
106func freemcache(c *mcache) {
107	systemstack(func() {
108		c.releaseAll()
109		stackcache_clear(c)
110
111		// NOTE(rsc,rlh): If gcworkbuffree comes back, we need to coordinate
112		// with the stealing of gcworkbufs during garbage collection to avoid
113		// a race where the workbuf is double-freed.
114		// gcworkbuffree(c.gcworkbuf)
115
116		lock(&mheap_.lock)
117		mheap_.cachealloc.free(unsafe.Pointer(c))
118		unlock(&mheap_.lock)
119	})
120}
121
122// getMCache is a convenience function which tries to obtain an mcache.
123//
124// Returns nil if we're not bootstrapping or we don't have a P. The caller's
125// P must not change, so we must be in a non-preemptible state.
126func getMCache(mp *m) *mcache {
127	// Grab the mcache, since that's where stats live.
128	pp := mp.p.ptr()
129	var c *mcache
130	if pp == nil {
131		// We will be called without a P while bootstrapping,
132		// in which case we use mcache0, which is set in mallocinit.
133		// mcache0 is cleared when bootstrapping is complete,
134		// by procresize.
135		c = mcache0
136	} else {
137		c = pp.mcache
138	}
139	return c
140}
141
142// refill acquires a new span of span class spc for c. This span will
143// have at least one free object. The current span in c must be full.
144//
145// Must run in a non-preemptible context since otherwise the owner of
146// c could change.
147func (c *mcache) refill(spc spanClass) {
148	// Return the current cached span to the central lists.
149	s := c.alloc[spc]
150
151	if s.allocCount != s.nelems {
152		throw("refill of span with free space remaining")
153	}
154	if s != &emptymspan {
155		// Mark this span as no longer cached.
156		if s.sweepgen != mheap_.sweepgen+3 {
157			throw("bad sweepgen in refill")
158		}
159		mheap_.central[spc].mcentral.uncacheSpan(s)
160
161		// Count up how many slots were used and record it.
162		stats := memstats.heapStats.acquire()
163		slotsUsed := int64(s.allocCount) - int64(s.allocCountBeforeCache)
164		atomic.Xadd64(&stats.smallAllocCount[spc.sizeclass()], slotsUsed)
165
166		// Flush tinyAllocs.
167		if spc == tinySpanClass {
168			atomic.Xadd64(&stats.tinyAllocCount, int64(c.tinyAllocs))
169			c.tinyAllocs = 0
170		}
171		memstats.heapStats.release()
172
173		// Count the allocs in inconsistent, internal stats.
174		bytesAllocated := slotsUsed * int64(s.elemsize)
175		gcController.totalAlloc.Add(bytesAllocated)
176
177		// Clear the second allocCount just to be safe.
178		s.allocCountBeforeCache = 0
179	}
180
181	// Get a new cached span from the central lists.
182	s = mheap_.central[spc].mcentral.cacheSpan()
183	if s == nil {
184		throw("out of memory")
185	}
186
187	if s.allocCount == s.nelems {
188		throw("span has no free space")
189	}
190
191	// Indicate that this span is cached and prevent asynchronous
192	// sweeping in the next sweep phase.
193	s.sweepgen = mheap_.sweepgen + 3
194
195	// Store the current alloc count for accounting later.
196	s.allocCountBeforeCache = s.allocCount
197
198	// Update heapLive and flush scanAlloc.
199	//
200	// We have not yet allocated anything new into the span, but we
201	// assume that all of its slots will get used, so this makes
202	// heapLive an overestimate.
203	//
204	// When the span gets uncached, we'll fix up this overestimate
205	// if necessary (see releaseAll).
206	//
207	// We pick an overestimate here because an underestimate leads
208	// the pacer to believe that it's in better shape than it is,
209	// which appears to lead to more memory used. See #53738 for
210	// more details.
211	usedBytes := uintptr(s.allocCount) * s.elemsize
212	gcController.update(int64(s.npages*pageSize)-int64(usedBytes), int64(c.scanAlloc))
213	c.scanAlloc = 0
214
215	c.alloc[spc] = s
216}
217
218// allocLarge allocates a span for a large object.
219func (c *mcache) allocLarge(size uintptr, noscan bool) *mspan {
220	if size+_PageSize < size {
221		throw("out of memory")
222	}
223	npages := size >> _PageShift
224	if size&_PageMask != 0 {
225		npages++
226	}
227
228	// Deduct credit for this span allocation and sweep if
229	// necessary. mHeap_Alloc will also sweep npages, so this only
230	// pays the debt down to npage pages.
231	deductSweepCredit(npages*_PageSize, npages)
232
233	spc := makeSpanClass(0, noscan)
234	s := mheap_.alloc(npages, spc)
235	if s == nil {
236		throw("out of memory")
237	}
238
239	// Count the alloc in consistent, external stats.
240	stats := memstats.heapStats.acquire()
241	atomic.Xadd64(&stats.largeAlloc, int64(npages*pageSize))
242	atomic.Xadd64(&stats.largeAllocCount, 1)
243	memstats.heapStats.release()
244
245	// Count the alloc in inconsistent, internal stats.
246	gcController.totalAlloc.Add(int64(npages * pageSize))
247
248	// Update heapLive.
249	gcController.update(int64(s.npages*pageSize), 0)
250
251	// Put the large span in the mcentral swept list so that it's
252	// visible to the background sweeper.
253	mheap_.central[spc].mcentral.fullSwept(mheap_.sweepgen).push(s)
254	s.limit = s.base() + size
255	s.initHeapBits(false)
256	return s
257}
258
259func (c *mcache) releaseAll() {
260	// Take this opportunity to flush scanAlloc.
261	scanAlloc := int64(c.scanAlloc)
262	c.scanAlloc = 0
263
264	sg := mheap_.sweepgen
265	dHeapLive := int64(0)
266	for i := range c.alloc {
267		s := c.alloc[i]
268		if s != &emptymspan {
269			slotsUsed := int64(s.allocCount) - int64(s.allocCountBeforeCache)
270			s.allocCountBeforeCache = 0
271
272			// Adjust smallAllocCount for whatever was allocated.
273			stats := memstats.heapStats.acquire()
274			atomic.Xadd64(&stats.smallAllocCount[spanClass(i).sizeclass()], slotsUsed)
275			memstats.heapStats.release()
276
277			// Adjust the actual allocs in inconsistent, internal stats.
278			// We assumed earlier that the full span gets allocated.
279			gcController.totalAlloc.Add(slotsUsed * int64(s.elemsize))
280
281			if s.sweepgen != sg+1 {
282				// refill conservatively counted unallocated slots in gcController.heapLive.
283				// Undo this.
284				//
285				// If this span was cached before sweep, then gcController.heapLive was totally
286				// recomputed since caching this span, so we don't do this for stale spans.
287				dHeapLive -= int64(s.nelems-s.allocCount) * int64(s.elemsize)
288			}
289
290			// Release the span to the mcentral.
291			mheap_.central[i].mcentral.uncacheSpan(s)
292			c.alloc[i] = &emptymspan
293		}
294	}
295	// Clear tinyalloc pool.
296	c.tiny = 0
297	c.tinyoffset = 0
298
299	// Flush tinyAllocs.
300	stats := memstats.heapStats.acquire()
301	atomic.Xadd64(&stats.tinyAllocCount, int64(c.tinyAllocs))
302	c.tinyAllocs = 0
303	memstats.heapStats.release()
304
305	// Update heapLive and heapScan.
306	gcController.update(dHeapLive, scanAlloc)
307}
308
309// prepareForSweep flushes c if the system has entered a new sweep phase
310// since c was populated. This must happen between the sweep phase
311// starting and the first allocation from c.
312func (c *mcache) prepareForSweep() {
313	// Alternatively, instead of making sure we do this on every P
314	// between starting the world and allocating on that P, we
315	// could leave allocate-black on, allow allocation to continue
316	// as usual, use a ragged barrier at the beginning of sweep to
317	// ensure all cached spans are swept, and then disable
318	// allocate-black. However, with this approach it's difficult
319	// to avoid spilling mark bits into the *next* GC cycle.
320	sg := mheap_.sweepgen
321	flushGen := c.flushGen.Load()
322	if flushGen == sg {
323		return
324	} else if flushGen != sg-2 {
325		println("bad flushGen", flushGen, "in prepareForSweep; sweepgen", sg)
326		throw("bad flushGen")
327	}
328	c.releaseAll()
329	stackcache_clear(c)
330	c.flushGen.Store(mheap_.sweepgen) // Synchronizes with gcStart
331}
332