// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package runtime import "unsafe" // Per-thread (in Go, per-P) cache for small objects. // No locking needed because it is per-thread (per-P). // // mcaches are allocated from non-GC'd memory, so any heap pointers // must be specially handled. // //go:notinheap type mcache struct { // The following members are accessed on every malloc, // so they are grouped here for better caching. next_sample int32 // trigger heap sample after allocating this many bytes local_scan uintptr // bytes of scannable heap allocated // Allocator cache for tiny objects w/o pointers. // See "Tiny allocator" comment in malloc.go. // tiny points to the beginning of the current tiny block, or // nil if there is no current tiny block. // // tiny is a heap pointer. Since mcache is in non-GC'd memory, // we handle it by clearing it in releaseAll during mark // termination. tiny uintptr tinyoffset uintptr local_tinyallocs uintptr // number of tiny allocs not counted in other stats // The rest is not accessed on every malloc. alloc [numSpanClasses]*mspan // spans to allocate from, indexed by spanClass stackcache [_NumStackOrders]stackfreelist // Local allocator stats, flushed during GC. local_nlookup uintptr // number of pointer lookups local_largefree uintptr // bytes freed for large objects (>maxsmallsize) local_nlargefree uintptr // number of frees for large objects (>maxsmallsize) local_nsmallfree [_NumSizeClasses]uintptr // number of frees for small objects (<=maxsmallsize) } // A gclink is a node in a linked list of blocks, like mlink, // but it is opaque to the garbage collector. // The GC does not trace the pointers during collection, // and the compiler does not emit write barriers for assignments // of gclinkptr values. Code should store references to gclinks // as gclinkptr, not as *gclink. type gclink struct { next gclinkptr } // A gclinkptr is a pointer to a gclink, but it is opaque // to the garbage collector. type gclinkptr uintptr // ptr returns the *gclink form of p. // The result should be used for accessing fields, not stored // in other data structures. func (p gclinkptr) ptr() *gclink { return (*gclink)(unsafe.Pointer(p)) } type stackfreelist struct { list gclinkptr // linked list of free stacks size uintptr // total size of stacks in list } // dummy MSpan that contains no free objects. var emptymspan mspan func allocmcache() *mcache { lock(&mheap_.lock) c := (*mcache)(mheap_.cachealloc.alloc()) unlock(&mheap_.lock) for i := range c.alloc { c.alloc[i] = &emptymspan } c.next_sample = nextSample() return c } func freemcache(c *mcache) { systemstack(func() { c.releaseAll() stackcache_clear(c) // NOTE(rsc,rlh): If gcworkbuffree comes back, we need to coordinate // with the stealing of gcworkbufs during garbage collection to avoid // a race where the workbuf is double-freed. // gcworkbuffree(c.gcworkbuf) lock(&mheap_.lock) purgecachedstats(c) mheap_.cachealloc.free(unsafe.Pointer(c)) unlock(&mheap_.lock) }) } // Gets a span that has a free object in it and assigns it // to be the cached span for the given sizeclass. Returns this span. func (c *mcache) refill(spc spanClass) { _g_ := getg() _g_.m.locks++ // Return the current cached span to the central lists. s := c.alloc[spc] if uintptr(s.allocCount) != s.nelems { throw("refill of span with free space remaining") } if s != &emptymspan { s.incache = false } // Get a new cached span from the central lists. s = mheap_.central[spc].mcentral.cacheSpan() if s == nil { throw("out of memory") } if uintptr(s.allocCount) == s.nelems { throw("span has no free space") } c.alloc[spc] = s _g_.m.locks-- } func (c *mcache) releaseAll() { for i := range c.alloc { s := c.alloc[i] if s != &emptymspan { mheap_.central[i].mcentral.uncacheSpan(s) c.alloc[i] = &emptymspan } } // Clear tinyalloc pool. c.tiny = 0 c.tinyoffset = 0 }