Skip to documentation
SLOP

alloc_fixed.Recycling

Reference alloc_fixed Recycling

Internal implementation documentation

Defined in alloc_fixed.

Recycling reuses memory chunks across repeated workloads to reduce allocation calls to an upstream backing allocator.

API (7)

Actions

Public operations.

Types and contracts

Public types and contracts.

Fields and members

Public fields and members.

No direct callersNo direct callsalloc_fixedRecycling
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Source: lib/alloc/fixed/src/fixed.zig:425

zig
/// `Recycling` reuses memory chunks across repeated workloads to reduce/// allocation calls to an upstream backing allocator. It tracks the count of/// outstanding live allocations within each chunk. When deallocations bring/// the live count of the active tail chunk to zero, that chunk is deactivated/// and reset for subsequent reuse. Because reusing an inactive chunk requires/// that its capacity and alignment satisfy the new request, subsequent/// workloads may still require new backing allocations if existing chunks/// lack sufficient size or alignment.////// ### Chunk deactivation and reuse constraints/// - It compacts no holes, so a chunk that sits before the tail and has emptied///   waits for every chunk behind it to empty too./// - Reusing an inactive chunk needs the alignment it was allocated at to meet///   or exceed the requested alignment, and needs room for the request./// - In `rawRemap`, growth that cannot happen in place returns `null`, and a///   caller going through `std.mem.Allocator.realloc` gets the allocate, copy,///   and free path, which is how a reallocation crosses chunks./// - In `rawResize`, shrinking returns `true` at once and leaves the frontier///   where it was, and growing in place looks at the active tail chunk alone.pub const Recycling = struct {    /// Internal chunk storage holding the buffer descriptors and the live    /// allocation counts that the methods work through. The owner maintains it,    /// so a caller accesses storage through `reset` and `discard` and takes no    /// copy of it and makes no direct changes.    inner: ChunkStorage,    const Self = @This();    /// Ceiling on how many chunks one instance holds at a time, fixed at 64    /// chunk descriptors and counting the inactive chunks kept for reuse.    pub const maximum_chunk_count = ChunkStorage.maximum_chunk_count;    /// Starts a `Recycling` instance over an allocator the caller already has.    /// It asserts that `initial_capacity > 0` and that    /// `maximum_capacity >= initial_capacity`. It allocates nothing here: the    /// first request that needs backing memory takes it.    pub fn init(        backing: Allocator,        initial_capacity: usize,        maximum_capacity: usize,    ) Self {        return .{ .inner = .init(            backing,            initial_capacity,            maximum_capacity,        ) };    }    /// Returns a borrowed `std.mem.Allocator` handle pointing at `self` to pass    /// to code that allocates. The `self` instance stays alive at one memory    /// address while the handle is in use.    pub fn allocator(self: *Self) Allocator {        return .{ .ptr = self, .vtable = &vtable };    }    /// Resets every tracked chunk and deactivates them for reuse so the next    /// round of work can start with the chunks it already has. It rewinds the    /// bump frontier of every tracked chunk and sets its live allocation count    /// to zero. The backing memory stays where it is, so later allocations    /// reuse the existing chunks when the size and the alignment fit. It leaves    /// `next_capacity` as it is and clears the descriptor exhaustion flag.    /// Every allocation returned before becomes invalid.    pub fn reset(self: *Self) void {        self.inner.reset();    }    /// Returns every tracked chunk back to the allocator it came from and    /// starts the growth schedule over. It frees in reverse order, puts    /// `next_capacity` back at `initial_capacity`, and clears the descriptor    /// exhaustion flag.    pub fn discard(self: *Self) void {        self.inner.discard();    }    /// Reports whether an allocation failed because all 64 chunk descriptors    /// were taken, helping a caller separate a full descriptor table from an    /// exhausted backing allocator because the two need different fixes. It    /// stays set until `reset()` or `discard()`.    pub fn metadataExhausted(self: *const Self) bool {        return self.inner.metadata_exhausted;    }    fn rawAlloc(        context: *anyopaque,        len: usize,        alignment: Alignment,        return_address: usize,    ) ?[*]u8 {        const self: *Self = @ptrCast(@alignCast(context));        return self.inner.allocate(.recycling, len, alignment, return_address);    }    fn rawResize(        context: *anyopaque,        memory: []u8,        alignment: Alignment,        new_len: usize,        return_address: usize,    ) bool {        const self: *Self = @ptrCast(@alignCast(context));        return self.inner.resize(memory, alignment, new_len, return_address);    }    fn rawRemap(        context: *anyopaque,        memory: []u8,        alignment: Alignment,        new_len: usize,        return_address: usize,    ) ?[*]u8 {        const self: *Self = @ptrCast(@alignCast(context));        return self.inner.remap(            .recycling,            memory,            alignment,            new_len,            return_address,        );    }    fn rawFree(        context: *anyopaque,        memory: []u8,        alignment: Alignment,        return_address: usize,    ) void {        const self: *Self = @ptrCast(@alignCast(context));        self.inner.free(.recycling, memory, alignment, return_address);    }    const vtable: Allocator.VTable = .{        .alloc = rawAlloc,        .resize = rawResize,        .remap = rawRemap,        .free = rawFree,    };};

Source: lib/alloc/fixed/src/root.zig:439

zig
/// `Recycling` reuses memory chunks across repeated workloads by tracking/// outstanding allocations across up to 64 chunk descriptors, including/// inactive chunks kept for reuse. When deallocations bring the live count of/// the active tail chunk to zero, that chunk is deactivated and reset for/// subsequent reuse. Because reusing an inactive chunk requires that its/// capacity and alignment satisfy the new request, subsequent workloads may/// still require new backing allocations if existing chunks lack sufficient/// size or alignment.pub const Recycling = fixed.Recycling;
Called byCallsNo direct callstest sourcelib.alloc.fixed.src.testtest: recycling chunks distinguish me...test sourcelib.alloc.fixed.src.testtest: recycling chunks leave maximum ...test sourcelib.alloc.fixed.src.testtest: recycling chunks release reloca...test sourcelib.alloc.fixed.src.testtest: recycling chunks retain aligned...test sourcelib.alloc.fixed.src.testtest: recycling chunks rewind alignme...+3 moreRecyclingallocator
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.alloc.fixed.src.testtest: recycling chunks distinguish me...test sourcelib.alloc.fixed.src.testtest: recycling chunks leave maximum ...test sourcelib.alloc.fixed.src.testtest: recycling chunks release reloca...test sourcelib.alloc.fixed.src.testtest: recycling chunks retain aligned...test sourcelib.alloc.fixed.src.testtest: recycling chunks rewind alignme...+3 moreprivate sourcelib.alloc.fixed.src.fixed.ChunkStoragediscardRecyclingdiscard
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.alloc.fixed.src.testtest: recycling chunks distinguish me...test sourcelib.alloc.fixed.src.testtest: recycling chunks leave maximum ...test sourcelib.alloc.fixed.src.testtest: recycling chunks preserve a liv...test sourcelib.alloc.fixed.src.testtest: recycling chunks release reloca...test sourcelib.alloc.fixed.src.testtest: recycling chunks retain aligned...+4 moreRecyclinginit
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.alloc.fixed.src.testtest: recycling chunks distinguish me...test sourcelib.alloc.fixed.src.testtest: recycling chunks leave maximum ...RecyclingmetadataExhausted
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.alloc.fixed.src.testtest: recycling chunks distinguish me...test sourcelib.alloc.fixed.src.testtest: recycling chunks leave maximum ...test sourcelib.alloc.fixed.src.testtest: recycling chunks retain aligned...test sourcelib.alloc.fixed.src.testtest: recycling chunks rewind retaine...private sourcelib.alloc.fixed.src.fixed.ChunkStorageresetRecyclingreset
Static calls · unresolved targets: 0 · external targets: 0.

Complete caller list for Recycling.allocator

8 direct callers.

Complete caller list for Recycling.discard

8 direct callers.

Complete caller list for Recycling.init

9 direct callers.

Audit

Definitions7
Public names7
Members1
Version26.7.0
Revisiondaab053ee433