silk.mem.arena.
A bump allocator over chunks it acquires from another allocator.
When to use#
Provide an Arena for Allocator when a phase of a program makes many allocations with
similar lifetimes, such as building a tree that is dropped all at once. Every container that
allocates through Allocator, such as List, Bytes, Box and Shared, works in it
unchanged.
Details#
Arena owns a child provider, passed to make, and asks it for chunks. An allocation bumps
a cursor through the current chunk and calls nothing else. Each chunk counts its live
allocations, so dropping an allocation is one atomic decrement and returns no memory by itself.
An allocation never borrows its arena. Dropping or resetting the arena returns every chunk that no live allocation points into to the child at once; a chunk that still holds a live allocation is returned when its last allocation drops, on whichever thread drops it.
Gotchas#
Memory freed inside a chunk is not reused: a List that grows in an arena leaves each earlier
buffer behind until the whole chunk is free. One long-lived allocation keeps its whole chunk
alive. Requests larger than half a chunk get a chunk of their own.
Examples#
Build a list in an arena#
import silk.mem.allocator { Allocator, OutOfMemoryError }
import silk.mem.arena { Arena }
import silk.core.effect { Effect }
import silk.collections.list { List }
effect fn build() -> i32
! OutOfMemoryError {
let mut arena = Arena.make(Allocator.systemAllocatorProvider())
let mut values = List<i32>.make()
run List<i32>.append(&mut values, 40)
|> Effect.provideMut<Allocator>(&mut arena)
run List<i32>.append(&mut values, 2)
|> Effect.provideMut<Allocator>(&mut arena)
return List<i32>.get(&values, 0) + List<i32>.get(&values, 1)
}
effect fn recover(error: OutOfMemoryError) -> i32 {
return 0
}
pub fn main() -> i32 {
return run Effect.catchAll(build(), recover)
}Import as Arena with import silk.mem.arena { Arena }.
Public declarations: 3.
ArenaOptions#
pub struct ArenaOptionsThe chunk sizes an Arena uses.
Field firstChunkBytes#
pub firstChunkBytes: usizeThe size in bytes of the first chunk.
Field maximumChunkBytes#
pub maximumChunkBytes: usizeThe largest size in bytes a regular chunk grows to. Each new chunk doubles the previous one up to this size.
Implementation ArenaOptions#
impl ArenaOptionsAssociated function default#
pub fn default() -> ArenaOptionsReturns the default sizes: a 4 KiB first chunk that doubles up to 1 MiB.
ArenaReset#
pub enum ArenaResetWhat Arena.reset does with the current chunk.
Release#
ReleaseRetires the current chunk; it is returned to the child once no allocation points into it.
RetainCapacity#
RetainCapacityKeeps the current chunk for the next allocations when no allocation points into it, and
otherwise retires it like Release.
Arena#
pub struct Arena<A>A bump allocator that provides Allocator from chunks of a child provider A.
When to use#
Provide an arena for Allocator when a phase of a program makes many allocations with similar
lifetimes, such as building a tree that is dropped all at once. Every container that allocates
through Allocator, such as List, Bytes, Box and Shared, works in it unchanged.
Details#
The arena owns its child and asks it for chunks. An allocation bumps a cursor through the current chunk and calls nothing else. Each chunk counts its live allocations, so dropping an allocation is one atomic decrement and returns no memory by itself.
An allocation never borrows its arena. Dropping or resetting the arena returns to the child at once each chunk that no live allocation points into. A chunk that still holds a live allocation is returned when its last allocation drops, on whichever thread drops it.
Allocation failure is the child's: the arena fails with OutOfMemoryError only when the child
refuses a chunk.
Gotchas#
Memory freed inside a chunk is not reused: a List that grows in an arena leaves each earlier
buffer behind until the whole chunk is free. One long-lived allocation keeps its whole chunk
alive. Requests larger than half a chunk get a chunk of their own.
Implementation Transferable for Arena<A>#
impl<A: Transferable> Transferable for Arena<A>Implementation Arena<A>#
impl<A> Arena<A>Associated function make#
pub fn make(child: A) -> Arena<A>Creates an arena over child with the default chunk sizes. It allocates nothing until the
first request.
Associated function withOptions#
pub fn withOptions(child: A, options: ArenaOptions) -> Arena<A>Creates an arena over child with explicit chunk sizes. It allocates nothing until the first
request.
Method reset#
pub fn reset(self: &mut Self, mode: ArenaReset) -> ()Stops allocating from the current chunk.
Details#
Allocations made before the reset stay valid. Their chunk is returned to the child when the
last of them drops, or now when none is alive. With ArenaReset.RetainCapacity, a current
chunk that no allocation points into stays for the next allocations.
Gotchas#
One long-lived allocation keeps its whole chunk alive after the reset.
Method available#
pub fn available(self: &Self) -> usizeReturns the bytes left in the current chunk before the arena asks its child for another.
Implementation Allocator for Arena<A>#
impl<A> Allocator for Arena<A>
where &mut A provides &Allocator from &mut AllocatorOperation allocate#
effect fn allocate(self: &mut Self, layout: Layout) -> Intrinsic.Allocation ! OutOfMemoryErrorImplementation Drop for Arena<A>#
impl<A> Drop for Arena<A>Operation drop#
fn drop(self: &mut Arena<A>) -> ()Category: Memory.
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2.