Struct blink_alloc::SyncBlinkAlloc
source · pub struct SyncBlinkAlloc<A: Allocator = Global> { /* private fields */ }
Expand description
Multi-threaded blink allocator.
Blink-allocator is arena-based allocator that allocates memory in growing chunks and serve allocations from them. When chunk is exhausted a new larger chunk is allocated.
Deallocation is no-op. BlinkAllocator
can be reset
to free all chunks except the last one, that will be reused.
Blink allocator aims to allocate a chunk large enough to serve all allocations between resets.
A shared and mutable reference to the SyncBlinkAlloc
implement
Allocator
trait.
When “nightly” feature is enabled, Allocator
trait is
core::alloc::Allocator
. Otherwise it is duplicated trait defined
in allocator-api2
.
Resetting blink allocator requires mutable borrow, so it is not possible
to do while shared borrow is alive. That matches requirement of
Allocator
trait - while Allocator
instance
(a shared reference to BlinkAlloc
) or any of its clones are alive,
allocated memory must be valid.
This version of blink-allocator is multi-threaded.
It can be used from multiple threads concurrently to allocate memory.
As mutable borrow is required to reset the allocator,
it is not possible to do when shared.
Internally it uses RwLock
and AtomicUsize
for synchronized
interior mutability. RwLock
is only write-locked when new chunk
must be allocated. The arena allocation is performed using lock-free
algorithm.
Still it is slower than single-threaded version BlinkAlloc
.
For best of both worlds LocalBlinkAlloc
can be created from
this allocator. LocalBlinkAlloc
will allocate chunks from this
allocator, but is single-threaded by itself.
Example
let mut blink = BlinkAlloc::new();
let layout = std::alloc::Layout::new::<[u32; 8]>();
let ptr = blink.allocate(layout).unwrap();
let ptr = NonNull::new(ptr.as_ptr() as *mut u8).unwrap(); // Method for this is unstable.
unsafe {
std::ptr::write(ptr.as_ptr().cast(), [1, 2, 3, 4, 5, 6, 7, 8]);
blink.deallocate(ptr, layout);
}
blink.reset();
Example that uses nightly’s allocator_api
let mut blink = BlinkAlloc::new();
let mut vec = Vec::new_in(&blink);
vec.push(1);
vec.extend(1..3);
vec.extend(3..10);
drop(vec);
blink.reset();
Implementations§
source§impl SyncBlinkAlloc<Global>
impl SyncBlinkAlloc<Global>
sourcepub const fn new() -> Self
pub const fn new() -> Self
Creates new blink allocator that uses global allocator to allocate memory chunks.
See SyncBlinkAlloc::new_in
for using custom allocator.
source§impl<A> SyncBlinkAlloc<A>where
A: Allocator,
impl<A> SyncBlinkAlloc<A>where A: Allocator,
sourcepub const fn new_in(allocator: A) -> Self
pub const fn new_in(allocator: A) -> Self
Creates new blink allocator that uses provided allocator to allocate memory chunks.
See SyncBlinkAlloc::new
for using global allocator.
sourcepub fn local(&self) -> LocalBlinkAlloc<'_, A>
pub fn local(&self) -> LocalBlinkAlloc<'_, A>
Creates a new thread-local blink allocator proxy that borrows from this multi-threaded allocator.
The local proxy allocator works faster and
allows more consistent memory reuse.
It can be recreated without resetting the multi-threaded allocator,
allowing SyncBlinkAlloc
to be warm-up and serve all allocations
from a single chunk without ever blocking.
Best works for fork-join style of parallelism. Create a local allocator for each thread/task. Reset after all threads/tasks are finished.
Examples
let mut blink = SyncBlinkAlloc::new();
for _ in 0..100 {
for i in 0..16 {
std::thread::scope(|_| {
let blink = blink.local();
let mut vec = Vec::new_in(&blink);
vec.push(i);
for j in i*2..i*30 {
vec.push(j); // Proxy will allocate enough memory to grow vec without reallocating on 2nd iteration and later.
}
});
}
blink.reset();
}
Trait Implementations§
source§impl<A> Allocator for &mut SyncBlinkAlloc<A>where
A: Allocator,
impl<A> Allocator for &mut SyncBlinkAlloc<A>where A: Allocator,
source§fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>
allocator_api
)source§unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout)
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout)
allocator_api
)ptr
. Read moresource§fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>
allocator_api
)allocate
, but also ensures that the returned memory is zero-initialized. Read moresource§unsafe fn grow(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout
) -> Result<NonNull<[u8]>, AllocError>
unsafe fn grow( &self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout ) -> Result<NonNull<[u8]>, AllocError>
allocator_api
)source§unsafe fn grow_zeroed(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout
) -> Result<NonNull<[u8]>, AllocError>
unsafe fn grow_zeroed( &self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout ) -> Result<NonNull<[u8]>, AllocError>
allocator_api
)grow
, but also ensures that the new contents are set to zero before being
returned. Read moresource§impl<A> Allocator for SyncBlinkAlloc<A>where
A: Allocator,
impl<A> Allocator for SyncBlinkAlloc<A>where A: Allocator,
source§fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>
allocator_api
)source§unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout)
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout)
allocator_api
)ptr
. Read moresource§fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>
allocator_api
)allocate
, but also ensures that the returned memory is zero-initialized. Read moresource§unsafe fn grow(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout
) -> Result<NonNull<[u8]>, AllocError>
unsafe fn grow( &self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout ) -> Result<NonNull<[u8]>, AllocError>
allocator_api
)source§unsafe fn grow_zeroed(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout
) -> Result<NonNull<[u8]>, AllocError>
unsafe fn grow_zeroed( &self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout ) -> Result<NonNull<[u8]>, AllocError>
allocator_api
)grow
, but also ensures that the new contents are set to zero before being
returned. Read more