fitzgen / bumpalo

A fast bump allocation arena for Rust

Home Page:https://docs.rs/bumpalo

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`Bump` not respecting allocation limit set

gimbling-away opened this issue · comments

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
  • 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 or bump.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(...))).