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//go:build goexperiment.arenas 6 7/* 8The arena package provides the ability to allocate memory for a collection 9of Go values and free that space manually all at once, safely. The purpose 10of this functionality is to improve efficiency: manually freeing memory 11before a garbage collection delays that cycle. Less frequent cycles means 12the CPU cost of the garbage collector is incurred less frequently. 13 14This functionality in this package is mostly captured in the Arena type. 15Arenas allocate large chunks of memory for Go values, so they're likely to 16be inefficient for allocating only small amounts of small Go values. They're 17best used in bulk, on the order of MiB of memory allocated on each use. 18 19Note that by allowing for this limited form of manual memory allocation 20that use-after-free bugs are possible with regular Go values. This package 21limits the impact of these use-after-free bugs by preventing reuse of freed 22memory regions until the garbage collector is able to determine that it is 23safe. Typically, a use-after-free bug will result in a fault and a helpful 24error message, but this package reserves the right to not force a fault on 25freed memory. That means a valid implementation of this package is to just 26allocate all memory the way the runtime normally would, and in fact, it 27reserves the right to occasionally do so for some Go values. 28*/ 29package arena 30 31import ( 32 "internal/reflectlite" 33 "unsafe" 34) 35 36// Arena represents a collection of Go values allocated and freed together. 37// Arenas are useful for improving efficiency as they may be freed back to 38// the runtime manually, though any memory obtained from freed arenas must 39// not be accessed once that happens. An Arena is automatically freed once 40// it is no longer referenced, so it must be kept alive (see runtime.KeepAlive) 41// until any memory allocated from it is no longer needed. 42// 43// An Arena must never be used concurrently by multiple goroutines. 44type Arena struct { 45 a unsafe.Pointer 46} 47 48// NewArena allocates a new arena. 49func NewArena() *Arena { 50 return &Arena{a: runtime_arena_newArena()} 51} 52 53// Free frees the arena (and all objects allocated from the arena) so that 54// memory backing the arena can be reused fairly quickly without garbage 55// collection overhead. Applications must not call any method on this 56// arena after it has been freed. 57func (a *Arena) Free() { 58 runtime_arena_arena_Free(a.a) 59 a.a = nil 60} 61 62// New creates a new *T in the provided arena. The *T must not be used after 63// the arena is freed. Accessing the value after free may result in a fault, 64// but this fault is also not guaranteed. 65func New[T any](a *Arena) *T { 66 return runtime_arena_arena_New(a.a, reflectlite.TypeOf((*T)(nil))).(*T) 67} 68 69// MakeSlice creates a new []T with the provided capacity and length. The []T must 70// not be used after the arena is freed. Accessing the underlying storage of the 71// slice after free may result in a fault, but this fault is also not guaranteed. 72func MakeSlice[T any](a *Arena, len, cap int) []T { 73 var sl []T 74 runtime_arena_arena_Slice(a.a, &sl, cap) 75 return sl[:len] 76} 77 78// Clone makes a shallow copy of the input value that is no longer bound to any 79// arena it may have been allocated from, returning the copy. If it was not 80// allocated from an arena, it is returned untouched. This function is useful 81// to more easily let an arena-allocated value out-live its arena. 82// T must be a pointer, a slice, or a string, otherwise this function will panic. 83func Clone[T any](s T) T { 84 return runtime_arena_heapify(s).(T) 85} 86 87//go:linkname reflect_arena_New reflect.arena_New 88func reflect_arena_New(a *Arena, typ any) any { 89 return runtime_arena_arena_New(a.a, typ) 90} 91 92//go:linkname runtime_arena_newArena 93func runtime_arena_newArena() unsafe.Pointer 94 95//go:linkname runtime_arena_arena_New 96func runtime_arena_arena_New(arena unsafe.Pointer, typ any) any 97 98// Mark as noescape to avoid escaping the slice header. 99// 100//go:noescape 101//go:linkname runtime_arena_arena_Slice 102func runtime_arena_arena_Slice(arena unsafe.Pointer, slice any, cap int) 103 104//go:linkname runtime_arena_arena_Free 105func runtime_arena_arena_Free(arena unsafe.Pointer) 106 107//go:linkname runtime_arena_heapify 108func runtime_arena_heapify(any) any 109