github.com/shogo82148/std@v1.22.1-0.20240327122250-4e474527810c/runtime/arena.go (about) 1 // Copyright 2022 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 // Implementation of (safe) user arenas. 6 // 7 // This file contains the implementation of user arenas wherein Go values can 8 // be manually allocated and freed in bulk. The act of manually freeing memory, 9 // potentially before a GC cycle, means that a garbage collection cycle can be 10 // delayed, improving efficiency by reducing GC cycle frequency. There are other 11 // potential efficiency benefits, such as improved locality and access to a more 12 // efficient allocation strategy. 13 // 14 // What makes the arenas here safe is that once they are freed, accessing the 15 // arena's memory will cause an explicit program fault, and the arena's address 16 // space will not be reused until no more pointers into it are found. There's one 17 // exception to this: if an arena allocated memory that isn't exhausted, it's placed 18 // back into a pool for reuse. This means that a crash is not always guaranteed. 19 // 20 // While this may seem unsafe, it still prevents memory corruption, and is in fact 21 // necessary in order to make new(T) a valid implementation of arenas. Such a property 22 // is desirable to allow for a trivial implementation. (It also avoids complexities 23 // that arise from synchronization with the GC when trying to set the arena chunks to 24 // fault while the GC is active.) 25 // 26 // The implementation works in layers. At the bottom, arenas are managed in chunks. 27 // Each chunk must be a multiple of the heap arena size, or the heap arena size must 28 // be divisible by the arena chunks. The address space for each chunk, and each 29 // corresponding heapArena for that address space, are eternally reserved for use as 30 // arena chunks. That is, they can never be used for the general heap. Each chunk 31 // is also represented by a single mspan, and is modeled as a single large heap 32 // allocation. It must be, because each chunk contains ordinary Go values that may 33 // point into the heap, so it must be scanned just like any other object. Any 34 // pointer into a chunk will therefore always cause the whole chunk to be scanned 35 // while its corresponding arena is still live. 36 // 37 // Chunks may be allocated either from new memory mapped by the OS on our behalf, 38 // or by reusing old freed chunks. When chunks are freed, their underlying memory 39 // is returned to the OS, set to fault on access, and may not be reused until the 40 // program doesn't point into the chunk anymore (the code refers to this state as 41 // "quarantined"), a property checked by the GC. 42 // 43 // The sweeper handles moving chunks out of this quarantine state to be ready for 44 // reuse. When the chunk is placed into the quarantine state, its corresponding 45 // span is marked as noscan so that the GC doesn't try to scan memory that would 46 // cause a fault. 47 // 48 // At the next layer are the user arenas themselves. They consist of a single 49 // active chunk which new Go values are bump-allocated into and a list of chunks 50 // that were exhausted when allocating into the arena. Once the arena is freed, 51 // it frees all full chunks it references, and places the active one onto a reuse 52 // list for a future arena to use. Each arena keeps its list of referenced chunks 53 // explicitly live until it is freed. Each user arena also maps to an object which 54 // has a finalizer attached that ensures the arena's chunks are all freed even if 55 // the arena itself is never explicitly freed. 56 // 57 // Pointer-ful memory is bump-allocated from low addresses to high addresses in each 58 // chunk, while pointer-free memory is bump-allocated from high address to low 59 // addresses. The reason for this is to take advantage of a GC optimization wherein 60 // the GC will stop scanning an object when there are no more pointers in it, which 61 // also allows us to elide clearing the heap bitmap for pointer-free Go values 62 // allocated into arenas. 63 // 64 // Note that arenas are not safe to use concurrently. 65 // 66 // In summary, there are 2 resources: arenas, and arena chunks. They exist in the 67 // following lifecycle: 68 // 69 // (1) A new arena is created via newArena. 70 // (2) Chunks are allocated to hold memory allocated into the arena with new or slice. 71 // (a) Chunks are first allocated from the reuse list of partially-used chunks. 72 // (b) If there are no such chunks, then chunks on the ready list are taken. 73 // (c) Failing all the above, memory for a new chunk is mapped. 74 // (3) The arena is freed, or all references to it are dropped, triggering its finalizer. 75 // (a) If the GC is not active, exhausted chunks are set to fault and placed on a 76 // quarantine list. 77 // (b) If the GC is active, exhausted chunks are placed on a fault list and will 78 // go through step (a) at a later point in time. 79 // (c) Any remaining partially-used chunk is placed on a reuse list. 80 // (4) Once no more pointers are found into quarantined arena chunks, the sweeper 81 // takes these chunks out of quarantine and places them on the ready list. 82 83 package runtime