| // 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" |
| |
| // Memory allocator, based on tcmalloc. |
| // http://goog-perftools.sourceforge.net/doc/tcmalloc.html |
| |
| // The main allocator works in runs of pages. |
| // Small allocation sizes (up to and including 32 kB) are |
| // rounded to one of about 100 size classes, each of which |
| // has its own free list of objects of exactly that size. |
| // Any free page of memory can be split into a set of objects |
| // of one size class, which are then managed using free list |
| // allocators. |
| // |
| // The allocator's data structures are: |
| // |
| // FixAlloc: a free-list allocator for fixed-size objects, |
| // used to manage storage used by the allocator. |
| // MHeap: the malloc heap, managed at page (4096-byte) granularity. |
| // MSpan: a run of pages managed by the MHeap. |
| // MCentral: a shared free list for a given size class. |
| // MCache: a per-thread (in Go, per-P) cache for small objects. |
| // MStats: allocation statistics. |
| // |
| // Allocating a small object proceeds up a hierarchy of caches: |
| // |
| // 1. Round the size up to one of the small size classes |
| // and look in the corresponding MCache free list. |
| // If the list is not empty, allocate an object from it. |
| // This can all be done without acquiring a lock. |
| // |
| // 2. If the MCache free list is empty, replenish it by |
| // taking a bunch of objects from the MCentral free list. |
| // Moving a bunch amortizes the cost of acquiring the MCentral lock. |
| // |
| // 3. If the MCentral free list is empty, replenish it by |
| // allocating a run of pages from the MHeap and then |
| // chopping that memory into objects of the given size. |
| // Allocating many objects amortizes the cost of locking |
| // the heap. |
| // |
| // 4. If the MHeap is empty or has no page runs large enough, |
| // allocate a new group of pages (at least 1MB) from the |
| // operating system. Allocating a large run of pages |
| // amortizes the cost of talking to the operating system. |
| // |
| // Freeing a small object proceeds up the same hierarchy: |
| // |
| // 1. Look up the size class for the object and add it to |
| // the MCache free list. |
| // |
| // 2. If the MCache free list is too long or the MCache has |
| // too much memory, return some to the MCentral free lists. |
| // |
| // 3. If all the objects in a given span have returned to |
| // the MCentral list, return that span to the page heap. |
| // |
| // 4. If the heap has too much memory, return some to the |
| // operating system. |
| // |
| // TODO(rsc): Step 4 is not implemented. |
| // |
| // Allocating and freeing a large object uses the page heap |
| // directly, bypassing the MCache and MCentral free lists. |
| // |
| // The small objects on the MCache and MCentral free lists |
| // may or may not be zeroed. They are zeroed if and only if |
| // the second word of the object is zero. A span in the |
| // page heap is zeroed unless s->needzero is set. When a span |
| // is allocated to break into small objects, it is zeroed if needed |
| // and s->needzero is set. There are two main benefits to delaying the |
| // zeroing this way: |
| // |
| // 1. stack frames allocated from the small object lists |
| // or the page heap can avoid zeroing altogether. |
| // 2. the cost of zeroing when reusing a small object is |
| // charged to the mutator, not the garbage collector. |
| // |
| // This C code was written with an eye toward translating to Go |
| // in the future. Methods have the form Type_Method(Type *t, ...). |
| |
| const ( |
| _PageShift = 13 |
| _PageSize = 1 << _PageShift |
| _PageMask = _PageSize - 1 |
| ) |
| |
| const ( |
| // _64bit = 1 on 64-bit systems, 0 on 32-bit systems |
| _64bit = 1 << (^uintptr(0) >> 63) / 2 |
| |
| // Computed constant. The definition of MaxSmallSize and the |
| // algorithm in msize.c produce some number of different allocation |
| // size classes. NumSizeClasses is that number. It's needed here |
| // because there are static arrays of this length; when msize runs its |
| // size choosing algorithm it double-checks that NumSizeClasses agrees. |
| _NumSizeClasses = 67 |
| |
| // Tunable constants. |
| _MaxSmallSize = 32 << 10 |
| |
| // Tiny allocator parameters, see "Tiny allocator" comment in malloc.go. |
| _TinySize = 16 |
| _TinySizeClass = 2 |
| |
| _FixAllocChunk = 16 << 10 // Chunk size for FixAlloc |
| _MaxMHeapList = 1 << (20 - _PageShift) // Maximum page length for fixed-size list in MHeap. |
| _HeapAllocChunk = 1 << 20 // Chunk size for heap growth |
| |
| // Per-P, per order stack segment cache size. |
| _StackCacheSize = 32 * 1024 |
| |
| // Number of orders that get caching. Order 0 is FixedStack |
| // and each successive order is twice as large. |
| // We want to cache 2KB, 4KB, 8KB, and 16KB stacks. Larger stacks |
| // will be allocated directly. |
| // Since FixedStack is different on different systems, we |
| // must vary NumStackOrders to keep the same maximum cached size. |
| // OS | FixedStack | NumStackOrders |
| // -----------------+------------+--------------- |
| // linux/darwin/bsd | 2KB | 4 |
| // windows/32 | 4KB | 3 |
| // windows/64 | 8KB | 2 |
| // plan9 | 4KB | 3 |
| _NumStackOrders = 4 - ptrSize/4*goos_windows - 1*goos_plan9 |
| |
| // Number of bits in page to span calculations (4k pages). |
| // On Windows 64-bit we limit the arena to 32GB or 35 bits. |
| // Windows counts memory used by page table into committed memory |
| // of the process, so we can't reserve too much memory. |
| // See http://golang.org/issue/5402 and http://golang.org/issue/5236. |
| // On other 64-bit platforms, we limit the arena to 128GB, or 37 bits. |
| // On 32-bit, we don't bother limiting anything, so we use the full 32-bit address. |
| _MHeapMap_TotalBits = (_64bit*goos_windows)*35 + (_64bit*(1-goos_windows))*37 + (1-_64bit)*32 |
| _MHeapMap_Bits = _MHeapMap_TotalBits - _PageShift |
| |
| _MaxMem = uintptr(1<<_MHeapMap_TotalBits - 1) |
| |
| // Max number of threads to run garbage collection. |
| // 2, 3, and 4 are all plausible maximums depending |
| // on the hardware details of the machine. The garbage |
| // collector scales well to 32 cpus. |
| _MaxGcproc = 32 |
| ) |
| |
| // A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).) |
| // Since assignments to mlink.next will result in a write barrier being preformed |
| // this can not be used by some of the internal GC structures. For example when |
| // the sweeper is placing an unmarked object on the free list it does not want the |
| // write barrier to be called since that could result in the object being reachable. |
| type mlink struct { |
| next *mlink |
| } |
| |
| // 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)) |
| } |
| |
| // sysAlloc obtains a large chunk of zeroed memory from the |
| // operating system, typically on the order of a hundred kilobytes |
| // or a megabyte. |
| // NOTE: sysAlloc returns OS-aligned memory, but the heap allocator |
| // may use larger alignment, so the caller must be careful to realign the |
| // memory obtained by sysAlloc. |
| // |
| // SysUnused notifies the operating system that the contents |
| // of the memory region are no longer needed and can be reused |
| // for other purposes. |
| // SysUsed notifies the operating system that the contents |
| // of the memory region are needed again. |
| // |
| // SysFree returns it unconditionally; this is only used if |
| // an out-of-memory error has been detected midway through |
| // an allocation. It is okay if SysFree is a no-op. |
| // |
| // SysReserve reserves address space without allocating memory. |
| // If the pointer passed to it is non-nil, the caller wants the |
| // reservation there, but SysReserve can still choose another |
| // location if that one is unavailable. On some systems and in some |
| // cases SysReserve will simply check that the address space is |
| // available and not actually reserve it. If SysReserve returns |
| // non-nil, it sets *reserved to true if the address space is |
| // reserved, false if it has merely been checked. |
| // NOTE: SysReserve returns OS-aligned memory, but the heap allocator |
| // may use larger alignment, so the caller must be careful to realign the |
| // memory obtained by sysAlloc. |
| // |
| // SysMap maps previously reserved address space for use. |
| // The reserved argument is true if the address space was really |
| // reserved, not merely checked. |
| // |
| // SysFault marks a (already sysAlloc'd) region to fault |
| // if accessed. Used only for debugging the runtime. |
| |
| // FixAlloc is a simple free-list allocator for fixed size objects. |
| // Malloc uses a FixAlloc wrapped around sysAlloc to manages its |
| // MCache and MSpan objects. |
| // |
| // Memory returned by FixAlloc_Alloc is not zeroed. |
| // The caller is responsible for locking around FixAlloc calls. |
| // Callers can keep state in the object but the first word is |
| // smashed by freeing and reallocating. |
| type fixalloc struct { |
| size uintptr |
| first unsafe.Pointer // go func(unsafe.pointer, unsafe.pointer); f(arg, p) called first time p is returned |
| arg unsafe.Pointer |
| list *mlink |
| chunk *byte |
| nchunk uint32 |
| inuse uintptr // in-use bytes now |
| stat *uint64 |
| } |
| |
| // Statistics. |
| // Shared with Go: if you edit this structure, also edit type MemStats in mem.go. |
| type mstats struct { |
| // General statistics. |
| alloc uint64 // bytes allocated and still in use |
| total_alloc uint64 // bytes allocated (even if freed) |
| sys uint64 // bytes obtained from system (should be sum of xxx_sys below, no locking, approximate) |
| nlookup uint64 // number of pointer lookups |
| nmalloc uint64 // number of mallocs |
| nfree uint64 // number of frees |
| |
| // Statistics about malloc heap. |
| // protected by mheap.lock |
| heap_alloc uint64 // bytes allocated and still in use |
| heap_sys uint64 // bytes obtained from system |
| heap_idle uint64 // bytes in idle spans |
| heap_inuse uint64 // bytes in non-idle spans |
| heap_released uint64 // bytes released to the os |
| heap_objects uint64 // total number of allocated objects |
| |
| // Statistics about allocation of low-level fixed-size structures. |
| // Protected by FixAlloc locks. |
| stacks_inuse uint64 // this number is included in heap_inuse above |
| stacks_sys uint64 // always 0 in mstats |
| mspan_inuse uint64 // mspan structures |
| mspan_sys uint64 |
| mcache_inuse uint64 // mcache structures |
| mcache_sys uint64 |
| buckhash_sys uint64 // profiling bucket hash table |
| gc_sys uint64 |
| other_sys uint64 |
| |
| // Statistics about garbage collector. |
| // Protected by mheap or stopping the world during GC. |
| next_gc uint64 // next gc (in heap_alloc time) |
| last_gc uint64 // last gc (in absolute time) |
| pause_total_ns uint64 |
| pause_ns [256]uint64 // circular buffer of recent gc pause lengths |
| pause_end [256]uint64 // circular buffer of recent gc end times (nanoseconds since 1970) |
| numgc uint32 |
| enablegc bool |
| debuggc bool |
| |
| // Statistics about allocation size classes. |
| |
| by_size [_NumSizeClasses]struct { |
| size uint32 |
| nmalloc uint64 |
| nfree uint64 |
| } |
| |
| tinyallocs uint64 // number of tiny allocations that didn't cause actual allocation; not exported to go directly |
| } |
| |
| var memstats mstats |
| |
| // Size classes. Computed and initialized by InitSizes. |
| // |
| // SizeToClass(0 <= n <= MaxSmallSize) returns the size class, |
| // 1 <= sizeclass < NumSizeClasses, for n. |
| // Size class 0 is reserved to mean "not small". |
| // |
| // class_to_size[i] = largest size in class i |
| // class_to_allocnpages[i] = number of pages to allocate when |
| // making new objects in class i |
| |
| var class_to_size [_NumSizeClasses]int32 |
| var class_to_allocnpages [_NumSizeClasses]int32 |
| var size_to_class8 [1024/8 + 1]int8 |
| var size_to_class128 [(_MaxSmallSize-1024)/128 + 1]int8 |
| |
| type mcachelist struct { |
| list *mlink |
| nlist uint32 |
| } |
| |
| type stackfreelist struct { |
| list gclinkptr // linked list of free stacks |
| size uintptr // total size of stacks in list |
| } |
| |
| // Per-thread (in Go, per-P) cache for small objects. |
| // No locking needed because it is per-thread (per-P). |
| 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_cachealloc intptr // bytes allocated (or freed) from cache since last lock of heap |
| // Allocator cache for tiny objects w/o pointers. |
| // See "Tiny allocator" comment in malloc.go. |
| tiny unsafe.Pointer |
| tinyoffset uintptr |
| local_tinyallocs uintptr // number of tiny allocs not counted in other stats |
| |
| // The rest is not accessed on every malloc. |
| alloc [_NumSizeClasses]*mspan // spans to allocate from |
| |
| stackcache [_NumStackOrders]stackfreelist |
| |
| sudogcache *sudog |
| |
| // 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) |
| } |
| |
| const ( |
| _KindSpecialFinalizer = 1 |
| _KindSpecialProfile = 2 |
| // Note: The finalizer special must be first because if we're freeing |
| // an object, a finalizer special will cause the freeing operation |
| // to abort, and we want to keep the other special records around |
| // if that happens. |
| ) |
| |
| type special struct { |
| next *special // linked list in span |
| offset uint16 // span offset of object |
| kind byte // kind of special |
| } |
| |
| // The described object has a finalizer set for it. |
| type specialfinalizer struct { |
| special special |
| fn *funcval |
| nret uintptr |
| fint *_type |
| ot *ptrtype |
| } |
| |
| // The described object is being heap profiled. |
| type specialprofile struct { |
| special special |
| b *bucket |
| } |
| |
| // An MSpan is a run of pages. |
| const ( |
| _MSpanInUse = iota // allocated for garbage collected heap |
| _MSpanStack // allocated for use by stack allocator |
| _MSpanFree |
| _MSpanListHead |
| _MSpanDead |
| ) |
| |
| type mspan struct { |
| next *mspan // in a span linked list |
| prev *mspan // in a span linked list |
| start pageID // starting page number |
| npages uintptr // number of pages in span |
| freelist gclinkptr // list of free objects |
| // sweep generation: |
| // if sweepgen == h->sweepgen - 2, the span needs sweeping |
| // if sweepgen == h->sweepgen - 1, the span is currently being swept |
| // if sweepgen == h->sweepgen, the span is swept and ready to use |
| // h->sweepgen is incremented by 2 after every GC |
| sweepgen uint32 |
| ref uint16 // capacity - number of objects in freelist |
| sizeclass uint8 // size class |
| incache bool // being used by an mcache |
| state uint8 // mspaninuse etc |
| needzero uint8 // needs to be zeroed before allocation |
| elemsize uintptr // computed from sizeclass or from npages |
| unusedsince int64 // first time spotted by gc in mspanfree state |
| npreleased uintptr // number of pages released to the os |
| limit uintptr // end of data in span |
| speciallock mutex // guards specials list |
| specials *special // linked list of special records sorted by offset. |
| } |
| |
| func (s *mspan) base() uintptr { |
| return uintptr(s.start << _PageShift) |
| } |
| |
| func (s *mspan) layout() (size, n, total uintptr) { |
| total = s.npages << _PageShift |
| size = s.elemsize |
| if size > 0 { |
| n = total / size |
| } |
| return |
| } |
| |
| // Every MSpan is in one doubly-linked list, |
| // either one of the MHeap's free lists or one of the |
| // MCentral's span lists. We use empty MSpan structures as list heads. |
| |
| // Central list of free objects of a given size. |
| type mcentral struct { |
| lock mutex |
| sizeclass int32 |
| nonempty mspan // list of spans with a free object |
| empty mspan // list of spans with no free objects (or cached in an mcache) |
| } |
| |
| // Main malloc heap. |
| // The heap itself is the "free[]" and "large" arrays, |
| // but all the other global data is here too. |
| type mheap struct { |
| lock mutex |
| free [_MaxMHeapList]mspan // free lists of given length |
| freelarge mspan // free lists length >= _MaxMHeapList |
| busy [_MaxMHeapList]mspan // busy lists of large objects of given length |
| busylarge mspan // busy lists of large objects length >= _MaxMHeapList |
| allspans **mspan // all spans out there |
| gcspans **mspan // copy of allspans referenced by gc marker or sweeper |
| nspan uint32 |
| sweepgen uint32 // sweep generation, see comment in mspan |
| sweepdone uint32 // all spans are swept |
| |
| // span lookup |
| spans **mspan |
| spans_mapped uintptr |
| |
| // range of addresses we might see in the heap |
| bitmap uintptr |
| bitmap_mapped uintptr |
| arena_start uintptr |
| arena_used uintptr |
| arena_end uintptr |
| arena_reserved bool |
| |
| // write barrier shadow data+heap. |
| // 64-bit systems only, enabled by GODEBUG=wbshadow=1. |
| shadow_enabled bool // shadow should be updated and checked |
| shadow_reserved bool // shadow memory is reserved |
| shadow_heap uintptr // heap-addr + shadow_heap = shadow heap addr |
| shadow_data uintptr // data-addr + shadow_data = shadow data addr |
| data_start uintptr // start of shadowed data addresses |
| data_end uintptr // end of shadowed data addresses |
| |
| // central free lists for small size classes. |
| // the padding makes sure that the MCentrals are |
| // spaced CacheLineSize bytes apart, so that each MCentral.lock |
| // gets its own cache line. |
| central [_NumSizeClasses]struct { |
| mcentral mcentral |
| pad [_CacheLineSize]byte |
| } |
| |
| spanalloc fixalloc // allocator for span* |
| cachealloc fixalloc // allocator for mcache* |
| specialfinalizeralloc fixalloc // allocator for specialfinalizer* |
| specialprofilealloc fixalloc // allocator for specialprofile* |
| speciallock mutex // lock for sepcial record allocators. |
| |
| // Malloc stats. |
| largefree uint64 // bytes freed for large objects (>maxsmallsize) |
| nlargefree uint64 // number of frees for large objects (>maxsmallsize) |
| nsmallfree [_NumSizeClasses]uint64 // number of frees for small objects (<=maxsmallsize) |
| } |
| |
| var mheap_ mheap |
| |
| const ( |
| // flags to malloc |
| _FlagNoScan = 1 << 0 // GC doesn't have to scan object |
| _FlagNoZero = 1 << 1 // don't zero memory |
| ) |
| |
| // NOTE: Layout known to queuefinalizer. |
| type finalizer struct { |
| fn *funcval // function to call |
| arg unsafe.Pointer // ptr to object |
| nret uintptr // bytes of return values from fn |
| fint *_type // type of first argument of fn |
| ot *ptrtype // type of ptr to object |
| } |
| |
| type finblock struct { |
| alllink *finblock |
| next *finblock |
| cnt int32 |
| _ int32 |
| fin [(_FinBlockSize - 2*ptrSize - 2*4) / unsafe.Sizeof(finalizer{})]finalizer |
| } |
| |
| // Information from the compiler about the layout of stack frames. |
| type bitvector struct { |
| n int32 // # of bits |
| bytedata *uint8 |
| } |
| |
| type stackmap struct { |
| n int32 // number of bitmaps |
| nbit int32 // number of bits in each bitmap |
| bytedata [1]byte // bitmaps, each starting on a 32-bit boundary |
| } |