Struct vulkano::memory::allocator::suballocator::BumpAllocator
source · [−]pub struct BumpAllocator { /* private fields */ }
Expand description
A suballocator which can allocate dynamically, but can only free all allocations at once.
With bump allocation, the used up space increases linearly as allocations are made and allocations can never be freed individually, which is why this algorithm is also called linear allocation. It is also known as arena allocation.
BumpAllocator
s are best suited for very short-lived (say a few frames at best) resources that
need to be allocated often (say each frame), to really take advantage of the performance gains.
For creating long-lived allocations, FreeListAllocator
is best suited. The way you would
typically use this allocator is to have one for each frame in flight. At the start of a frame,
you reset it and allocate your resources with it. You write to the resources, render with them,
and drop them at the end of the frame.
See also the Suballocator
implementation.
Algorithm
What happens is that every time you make an allocation, you receive one with an offset corresponding to the free start within the region, and then the free start is bumped, so that following allocations wouldn’t alias it. As you can imagine, this is extremely fast, because it doesn’t need to keep a free-list. It only needs to do a few additions and comparisons. But beware, fast is about all this is. It is horribly memory inefficient when used wrong, and is very susceptible to memory leaks.
Once you know that you are done with the allocations, meaning you know they have all been
dropped, you can safely reset the allocator using the try_reset
method as long as the
allocator is not shared between threads. It is hard to safely reset a bump allocator that is
used concurrently. In such a scenario it’s best not to reset it at all and instead drop it once
it reaches the end of the region, freeing the region to a higher level in the hierarchy
once all threads have dropped their reference to the allocator. This is one of the reasons you
are generally advised to use one BumpAllocator
per thread if you can.
Efficiency
Allocation is O(1), and so is resetting the allocator (freeing all allocations). Allocation
is always lock-free, and most of the time even wait-free. The only case in which it is not
wait-free is if a lot of allocations are made concurrently, which results in CPU-level
contention. Therefore, if you for example need to allocate a lot of buffers each frame from
multiple threads, you might get better performance by using one BumpAllocator
per thread.
The reason synchronization can be avoided entirely is that the created allocations can be
dropped without needing to talk back to the allocator to free anything. The other allocation
algorithms all have a free-list which needs to be modified once an allocation is dropped. Since
Vulkano’s buffers and images are Sync
, that means that even if the allocator only allocates
from one thread, it can still be used to free from multiple threads.
Implementations
sourceimpl BumpAllocator
impl BumpAllocator
sourcepub fn new(region: MemoryAlloc) -> Arc<Self>
pub fn new(region: MemoryAlloc) -> Arc<Self>
Creates a new BumpAllocator
for the given region.
Panics
- Panics if
region
is a dedicated allocation.
sourcepub fn try_reset(self: &mut Arc<Self>) -> Result<(), BumpAllocatorResetError>
pub fn try_reset(self: &mut Arc<Self>) -> Result<(), BumpAllocatorResetError>
Resets the free start back to the beginning of the region if there are no other strong references to the allocator.
sourcepub unsafe fn reset_unchecked(&self)
pub unsafe fn reset_unchecked(&self)
Resets the free-start to the beginning of the region without checking if there are other strong references to the allocator.
This could be useful if you cloned the Arc
yourself, and can guarantee that no
allocations currently hold a reference to it.
As a safe alternative, you can let the Arc
do all the work. Simply drop it once it
reaches the end of the region. After all threads do that, the region will be freed to the
next level up the hierarchy. If you only use the allocator on one thread and need shared
ownership, you can use Rc<RefCell<Arc<BumpAllocator>>>
together with try_reset
for a
safe alternative as well.
Safety
- All allocations made with the allocator must have been dropped.