github.com/aloncn/graphics-go@v0.0.1/src/runtime/mcache.go (about) 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 5 package runtime 6 7 import "unsafe" 8 9 // Per-thread (in Go, per-P) cache for small objects. 10 // No locking needed because it is per-thread (per-P). 11 // 12 // mcaches are allocated from non-GC'd memory, so any heap pointers 13 // must be specially handled. 14 type mcache struct { 15 // The following members are accessed on every malloc, 16 // so they are grouped here for better caching. 17 next_sample int32 // trigger heap sample after allocating this many bytes 18 local_scan uintptr // bytes of scannable heap allocated 19 20 // Allocator cache for tiny objects w/o pointers. 21 // See "Tiny allocator" comment in malloc.go. 22 23 // tiny points to the beginning of the current tiny block, or 24 // nil if there is no current tiny block. 25 // 26 // tiny is a heap pointer. Since mcache is in non-GC'd memory, 27 // we handle it by clearing it in releaseAll during mark 28 // termination. 29 tiny uintptr 30 tinyoffset uintptr 31 local_tinyallocs uintptr // number of tiny allocs not counted in other stats 32 33 // The rest is not accessed on every malloc. 34 alloc [_NumSizeClasses]*mspan // spans to allocate from 35 36 stackcache [_NumStackOrders]stackfreelist 37 38 // Local allocator stats, flushed during GC. 39 local_nlookup uintptr // number of pointer lookups 40 local_largefree uintptr // bytes freed for large objects (>maxsmallsize) 41 local_nlargefree uintptr // number of frees for large objects (>maxsmallsize) 42 local_nsmallfree [_NumSizeClasses]uintptr // number of frees for small objects (<=maxsmallsize) 43 } 44 45 // A gclink is a node in a linked list of blocks, like mlink, 46 // but it is opaque to the garbage collector. 47 // The GC does not trace the pointers during collection, 48 // and the compiler does not emit write barriers for assignments 49 // of gclinkptr values. Code should store references to gclinks 50 // as gclinkptr, not as *gclink. 51 type gclink struct { 52 next gclinkptr 53 } 54 55 // A gclinkptr is a pointer to a gclink, but it is opaque 56 // to the garbage collector. 57 type gclinkptr uintptr 58 59 // ptr returns the *gclink form of p. 60 // The result should be used for accessing fields, not stored 61 // in other data structures. 62 func (p gclinkptr) ptr() *gclink { 63 return (*gclink)(unsafe.Pointer(p)) 64 } 65 66 type stackfreelist struct { 67 list gclinkptr // linked list of free stacks 68 size uintptr // total size of stacks in list 69 } 70 71 // dummy MSpan that contains no free objects. 72 var emptymspan mspan 73 74 func allocmcache() *mcache { 75 lock(&mheap_.lock) 76 c := (*mcache)(mheap_.cachealloc.alloc()) 77 unlock(&mheap_.lock) 78 memclr(unsafe.Pointer(c), unsafe.Sizeof(*c)) 79 for i := 0; i < _NumSizeClasses; i++ { 80 c.alloc[i] = &emptymspan 81 } 82 c.next_sample = nextSample() 83 return c 84 } 85 86 func freemcache(c *mcache) { 87 systemstack(func() { 88 c.releaseAll() 89 stackcache_clear(c) 90 91 // NOTE(rsc,rlh): If gcworkbuffree comes back, we need to coordinate 92 // with the stealing of gcworkbufs during garbage collection to avoid 93 // a race where the workbuf is double-freed. 94 // gcworkbuffree(c.gcworkbuf) 95 96 lock(&mheap_.lock) 97 purgecachedstats(c) 98 mheap_.cachealloc.free(unsafe.Pointer(c)) 99 unlock(&mheap_.lock) 100 }) 101 } 102 103 // Gets a span that has a free object in it and assigns it 104 // to be the cached span for the given sizeclass. Returns this span. 105 func (c *mcache) refill(sizeclass int32) *mspan { 106 _g_ := getg() 107 108 _g_.m.locks++ 109 // Return the current cached span to the central lists. 110 s := c.alloc[sizeclass] 111 if s.freelist.ptr() != nil { 112 throw("refill on a nonempty span") 113 } 114 if s != &emptymspan { 115 s.incache = false 116 } 117 118 // Get a new cached span from the central lists. 119 s = mheap_.central[sizeclass].mcentral.cacheSpan() 120 if s == nil { 121 throw("out of memory") 122 } 123 if s.freelist.ptr() == nil { 124 println(s.ref, (s.npages<<_PageShift)/s.elemsize) 125 throw("empty span") 126 } 127 c.alloc[sizeclass] = s 128 _g_.m.locks-- 129 return s 130 } 131 132 func (c *mcache) releaseAll() { 133 for i := 0; i < _NumSizeClasses; i++ { 134 s := c.alloc[i] 135 if s != &emptymspan { 136 mheap_.central[i].mcentral.uncacheSpan(s) 137 c.alloc[i] = &emptymspan 138 } 139 } 140 // Clear tinyalloc pool. 141 c.tiny = 0 142 c.tinyoffset = 0 143 }