`Bump` not respecting allocation limit set
gimbling-away opened this issue · comments
Hello \o/
I am currently trying out the set_allocation_limit
API of Bump
— Perhaps I'm misunderstanding how it affects the arena, but the limit seems to be completely ignored? I'd really appreciate some help on this! <3
Thanks for filing an issue.
That example is setting the allocation limit after allocating a chunk. But the allocated chunk could have been with a little more capacity than requested for a variety of reasons, so you might already have more capacity than the limit by the time you set the limit. Note that the set_allocation_limit
docs have this tidbit:
The allocation limit is only enforced when allocating new backing chunks for a Bump. Updating the allocation limit will not affect existing allocations or any future allocations within the Bump's current chunk.
So if you set the limit and then allocate, you should run into the limit and start getting allocation failures.
Ah, thanks! :)
Is there anyway I can reserve capacity after initialization? (Similar to Vec::reserve
) Since I need to set the limit before reserving capacity. I couldn't find a similar API
Not really after you've already allocated, because if there isn't enough capacity in the current chunk to satisfy the reservation request, we can't resize the current chunk that the Bump
is currently parceling out. We would have to allocate a new chunk for the remaining capacity that is left over after accounting for the capacity in this chunk, but bumpalo's architecture doesn't allow for "future chunks" that are pre-allocated before we are done with the current chunk. And also, it isn't clear whether that capacity needs to be contiguous for one big allocation (eg a single big slice) or can be non-contiguous for a bunch of small allocations (eg a hundred usize
allocations).
If you wanted to pre-allocate space for one big chunk, you could do something like bump.dealloc(bump.alloc_layout(Layout::new(capacity, 1)))
. But note that, if the current chunk doesn't have capacity for that layout, this will allocate a new chunk that does have capacity for that layout, and then even after the dealloc
the Bump
will allocate out of that new chunk. This means that any leftover capacity in the original chunk is effectively leaked until the bump is reset or dropped. Here is a concrete example:
- create a new bump
- starts with zero capacity
- allocate a
u16
- bump doesn't have enough capacity for the
u16
- so it allocates a new chunk with (say) 512 bytes of capacity
- the
u16
is allocated within that chunk - there is 510 bytes of capacity remaining
- bump doesn't have enough capacity for the
- do the
bump.dealloc(bump.alloc_layout(Layout::new(512, 1))
thing to reserve 512 bytes of capacity- current chunks capacity of 510 is not large enough to satisfy request for 512 bytes
- new chunk is allocated that can fit 512 bytes
- old chunk's 510 bytes of previously available capacity will now "leak" and not be used for any bump allocations until the
bump
is dropped orbump.reset()
is called
FWIW, you can check the remaining capacity in the chunk via bump.chunk_capacity()
and determine whether it is worth it to do the reservation trick or not, based on how much capacity would be "leaked".
But yeah, to sum up: there isn't a simple general solution here, the way there is for Vec
, and so I don't think it makes sense to add a bump.reserve(capacity)
method because there are too many subtleties and potential trade offs involved.
To be clear, my usage in specific is using Bump
is fixed to a specific amount of memory, hence the original snippet :)
But I understand your point, thanks! (I might try out dealloc(alloc(...))
).