Module allocator
Memory allocation abstractions and global allocator interface.
Stability
stable — Layout, AllocError, GlobalAllocator, and the pluggable
surface: Allocator (a context pointer plus a vtable, Zig's
std.mem.Allocator shape; it and AllocatorVTable are defined in the
prelude, this module holds their methods), with_allocator,
current_allocator. The
vtable (alloc, realloc, free, context first) and the 16-byte owner
prefix are frozen: codegen writes the same prefix for every RC object a
scope places (plans/archive/EXPLICIT_ALLOCATORS.md). Implementors: the global
allocator, std/arena.yo's Arena, and a counting allocator in
tests/arena.test.yo.
Explicit allocators and the owner prefix
Every block handed out by Allocator.alloc carries a 16-byte prefix
immediately before the returned pointer, holding the allocator's ctx and
vtable. Allocator.realloc and Allocator.free read it, so a block is
always released to the allocator that made it, whoever releases it and on
whichever thread. Implementors never see the prefix: their alloc hands out
a raw block 16 bytes larger than asked, and this module owns the layout.
The same layout is emitted by codegen for reference-counted objects placed
by an explicit allocator, so the two sides must never diverge.
Types
Describes the size and alignment requirements for a memory allocation.
Fields
| Name | Type | Description |
|---|---|---|
size | usize | Size in bytes. |
alignment | usize | Alignment in bytes (must be a power of two). |
Memory allocation error variants.
Variants
| Variant | Fields | Description |
|---|---|---|
OutOfMemory | Allocator ran out of memory. |
Methods
clone : (AllocError) fn(inout(self) : AllocError) -> AllocErrorFunctions
Check if allocating count elements of type T would overflow usize.
Parameters
| Name | Type | Notes |
|---|---|---|
T | Type | comptime |
count | usize |
Returns: bool
Evaluate f() with alloc as the thread's current allocator.
Every reference-counted object created while f runs — ref struct and
enum constructors, box/arc, dyn boxes, Iso values and io.async
tasks, including the ones std creates on the caller's behalf — comes from
alloc, and its release is routed back to alloc wherever and whenever its
last reference dies. A task created in the scope keeps it across
suspensions: work it does after with_allocator has returned still lands
in alloc. The previous allocator is restored when f returns or unwinds.
The scope is per thread: a spawn body starts on the global allocator
(pass the Allocator value in and call with_allocator there). Container
buffers created in the scope (ArrayList.new(), HashMap.new(),
Deque.new(), and String/StringBuilder/HashSet through them) live in
alloc too; new_in(alloc) names an allocator outside a scope.
Runtime only: a compile-time call is an extern call.
arena := Arena.new(usize(1) << usize(20));
p := with_allocator(arena.allocator(), () => Point(x : i32(3), y : i32(4)));
Type Parameters
| Name | Type | Notes |
|---|---|---|
T | Type | comptime |
Parameters
| Name | Type | Notes | Description |
|---|---|---|---|
alloc | Allocator | Allocate | |
f | Impl(Fn() -> T) |
Returns: T
Constants
The process-wide global allocator: the one --allocator selects (system
by default, mimalloc or fixed).
Two allocation families live here and they are not interchangeable:
| allocate with | release with |
|---|---|
malloc / calloc / realloc |
free |
aligned_alloc |
aligned_free |
Crossing the two corrupts the heap on Windows, where the aligned family is
the CRT's separate _aligned_malloc / _aligned_free pair.
Under --allocator fixed there is ONE family: aligned_free and free
are the same function, so the split above cannot bite (the region's
aligned_alloc splits a misaligned front piece back into the pool and
every release path coalesces through the same TLSF free).
Value: source_namespace_18332534865118561964_0(malloc: <unknown: fn(size : usize) -> ?(*(void))>, calloc: <unknown: fn(nmemb : usize, size : usize) -> ?(*(void))>, realloc: <unknown: fn(ptr : ?(*(void)), size : usize) -> ?(*(void))>, free: <unknown: fn(ptr : ?(*(void))) -> unit>, aligned_alloc: <fn(alignment, size)>, aligned_free: <unknown: fn(ptr : ?(*(void))) -> unit>)
Size of the owner prefix in front of every Allocator.alloc block. 16 keeps
the returned pointer aligned for any scalar the plain family serves.
Value: 16