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