-
Notifications
You must be signed in to change notification settings - Fork 118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fallback when allocating a new chunk fails #111
Conversation
when twice the current footer size cannot be allocated. This is done by modifying the Bump new_chunk parameters, it now asks for the chunk size instead of computing it on its size.
src/lib.rs
Outdated
debug_assert!(size >= old_size_with_footer.unwrap_or(0) * 2); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about this change, what do you think? Do I need to move it to the alloc_layout_slow
method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you instead debug_assert!
the property that the new chunk can hold the requested_layout
if any?
I tried another allocating policy, where it always try to allocate half the previously tried allocated size, starting from twice the size of the last allocated chunk and stopping when the size is smaller than the default chunk size. I implemented this because I again faced an allocation error due to the fact that the remaining memory what a little bit less than half the size of the last allocated chunk size (the current policy of this PR). |
3bf3588
to
d05ae1a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't have this behavior in new_chunk
directly because that will break with_capacity
's and try_with_capacity
's guarantees that if it successfully returns then you have that much given capacity.
I think the way to go is by defining a new function that wraps new_chunk
in a loop and tries to allocate double the current chunk, then the current chunk, then half the current chunk, then a quarter, etc... and fails if allocating the default chunk size fails or if it can't allocate something large enough for the requested allocation's layout.
Does that make sense?
It totally makes sense and this is why I didn't modify the However, I modified the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @Kerollmops! This looks good to me, modulo the little suggestions below. After those are addressed, I'll be happy to merge this! Thanks again!
src/lib.rs
Outdated
debug_assert!(size >= old_size_with_footer.unwrap_or(0) * 2); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you instead debug_assert!
the property that the new chunk can hold the requested_layout
if any?
src/lib.rs
Outdated
// smaller than the default footer size. | ||
let mut base_size = (current_layout.size() - FOOTER_SIZE).checked_mul(2)?; | ||
let sizes = iter::from_fn(|| { | ||
if base_size >= DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if base_size >= DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER { | |
if base_size >= DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER && base_size >= layout.size { |
This isn't technically 100% necessary for correctness, since Bump::new_chunk
will round up to the requested layout's size/align. However, consider the scenario where the requested size is very large and the global allocator can't fulfill it: if we didn't have this additional check, we would ask for smaller and smaller chunks, but new_chunk
would have to round those chunk sizes up to the exact same requested layout size every time, effectively making a pretty-much-known-to-fail malloc call log n
times.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could also combine the checks with something like this:
let min_new_chunk_size = layout.size.max(DEFAULT_CHUNK_SIZE_WITHOUT_FOOTER);
let sizes = iter::from_fn(|| {
if base_size >= min_new_chunk_size {
// ...
} else {
// ...
}
});
src/lib.rs
Outdated
// As a sane default, we want our new allocation to be about twice as | ||
// big as the previous allocation. If the global allocator refuses it, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Teensy tiny nitpick over wording.
// As a sane default, we want our new allocation to be about twice as | |
// big as the previous allocation. If the global allocator refuses it, | |
// By default, we want our new chunk to be about twice as | |
// big as the previous chunk. If the global allocator refuses it, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Thanks for your patience with the multiple rounds of review.
Looks like there are errors in CI: Can you reproduce this locally? |
Hey, yes, I just fixed it, what do you think?
No worries, it is completely understandable 😃 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!!
When the global allocator is unable to allocate a new chunk, mostly due to the size, the
Bump
struct was either panicking or returning anAllocErr
. This PR, discussed in a comment, changes the policy of theBump::alloc_layout_slow
:None
instead of the footer, the same behavior as before.Trying to allocate half the size of the last chunk helps in allocating the whole available memory, it creates smaller allocations that will more easily fit in the available global memory.