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.
allocator: Returns a borrowedstd.mem.Allocatorhandle pointing atselfto pass to code that allocates.discard: Returns every tracked chunk back to the allocator it came from and starts the growth schedule over.init: Starts aRecyclinginstance over an allocator the caller already has.metadataExhausted: 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.reset: Resets every tracked chunk and deactivates them for reuse so the next round of work can start with the chunks it already has.
Types and contracts
Public types and contracts.
maximum_chunk_count: Ceiling on how many chunks one instance holds at a time, fixed at 64 chunk descriptors and counting the inactive chunks kept for reuse.
Fields and members
Public fields and members.
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;Complete caller list for Recycling.allocator
8 direct callers.
lib.alloc.fixed.src.test.test_recycling_chunks_distinguish_metadata_exhaustion[function] — test source atlib/alloc/fixed/src/test.zig:210in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_leave_maximum_plus_one_to_the_backing_owner[function] — test source atlib/alloc/fixed/src/test.zig:186in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_release_relocated_allocations[function] — test source atlib/alloc/fixed/src/test.zig:303in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_retain_aligned_storage_after_first_acquisition[function] — test source atlib/alloc/fixed/src/test.zig:166in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_rewind_alignment_padding_across_chunks[function] — test source atlib/alloc/fixed/src/test.zig:277in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_rewind_retained_storage_without_backing_growth[function] — test source atlib/alloc/fixed/src/test.zig:113in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_stay_distinct_from_retained_output_chunks[function] — test source atlib/alloc/fixed/src/test.zig:103in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_unwind_a_failed_nested_chunk_transaction[function] — test source atlib/alloc/fixed/src/test.zig:246in nearest public ownerlib.alloc.fixed.src.test
Complete caller list for Recycling.discard
8 direct callers.
lib.alloc.fixed.src.test.test_recycling_chunks_distinguish_metadata_exhaustion[function] — test source atlib/alloc/fixed/src/test.zig:210in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_leave_maximum_plus_one_to_the_backing_owner[function] — test source atlib/alloc/fixed/src/test.zig:186in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_release_relocated_allocations[function] — test source atlib/alloc/fixed/src/test.zig:303in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_retain_aligned_storage_after_first_acquisition[function] — test source atlib/alloc/fixed/src/test.zig:166in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_rewind_alignment_padding_across_chunks[function] — test source atlib/alloc/fixed/src/test.zig:277in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_rewind_retained_storage_without_backing_growth[function] — test source atlib/alloc/fixed/src/test.zig:113in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_stay_distinct_from_retained_output_chunks[function] — test source atlib/alloc/fixed/src/test.zig:103in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_unwind_a_failed_nested_chunk_transaction[function] — test source atlib/alloc/fixed/src/test.zig:246in nearest public ownerlib.alloc.fixed.src.test
Complete caller list for Recycling.init
9 direct callers.
lib.alloc.fixed.src.test.test_recycling_chunks_distinguish_metadata_exhaustion[function] — test source atlib/alloc/fixed/src/test.zig:210in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_leave_maximum_plus_one_to_the_backing_owner[function] — test source atlib/alloc/fixed/src/test.zig:186in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_preserve_a_live_sibling_while_alternating[function] — test source atlib/alloc/fixed/src/test.zig:136in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_release_relocated_allocations[function] — test source atlib/alloc/fixed/src/test.zig:303in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_retain_aligned_storage_after_first_acquisition[function] — test source atlib/alloc/fixed/src/test.zig:166in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_rewind_alignment_padding_across_chunks[function] — test source atlib/alloc/fixed/src/test.zig:277in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_rewind_retained_storage_without_backing_growth[function] — test source atlib/alloc/fixed/src/test.zig:113in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_stay_distinct_from_retained_output_chunks[function] — test source atlib/alloc/fixed/src/test.zig:103in nearest public ownerlib.alloc.fixed.src.testlib.alloc.fixed.src.test.test_recycling_chunks_unwind_a_failed_nested_chunk_transaction[function] — test source atlib/alloc/fixed/src/test.zig:246in nearest public ownerlib.alloc.fixed.src.test
Audit
| Definitions | 7 |
|---|---|
| Public names | 7 |
| Members | 1 |
| Version | 26.7.0 |
| Revision | daab053ee433 |