-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Allocators, take III #1398
Allocators, take III #1398
Conversation
cc @gankro |
An |
I am quite sure that arithmetic overflow during computation of the input size is an OOM basically by definition. |
Not really. If you are running 4GiB of RAM with overcommit/swap disabled and try to malloc all of it, your malloc is going to fail and will not succeed until the system's configuration changes. Of course, allocators SHOULD NOT leak memory on dealloc. |
@arielb1 wrote:
True. I spent a little while trying to find weasel wording here that would cover zero sized allocations (which are also an Error in this API). I don't remember offhand how each part of the text addressed it, but the the phrasing here is not great. |
Hmm, okay yes I see, the returned blocks alias the embedded array, but LLVM is allowed to assume that only the |
... But this does not seem quite right to me ... this would allow multiple clients to reference the pool, but the point of using Hmm. I am not sure how to resolve this for the example. |
Really glad that this topic is getting some love. Ironically, I had just started rehashing my allocators crate for the first time in a month, including adding a re-implementation of a few key data structures. I am slightly doubtful of the necessity for an associated In the case you describe with Consider this extremely contrived example. fn use_alloc<A>(alloc: A) where A: Allocator {
let my_block = alloc::Kind { size: 1024, align: 8 };
let my_addr;
// try the allocation until it works or hits a non-transient error
loop {
match alloc.alloc(&my_block) => {
Ok(addr) => { my_addr = addr; break; }
Err(e) => {
if !e.is_transient() {
// panic or something
}
}
}
}
// use my_addr here
} I know we're trying to move above and beyond the old-school mechanisms of |
Huge fan of this concept, I'm actually currently struggling with the fact that I can't use a specific allocator for any of the libstd data structures, which would make my life a lot easier working with shared memory pages... |
Bikeshedding, but is the name "Kind" going to get confusing if we ever get higher-kinded anything? |
The points you mention are important, but the raison d'être of the This RFC explores this tangentially for GC, but I would like to also see some examples for computing devices (like GPGPUs or XeonPhis), for example:
[0] From the Alexander Stepanov and Meng Lee, The Standard Template Library, HP Technical Report HPL-95-11(R.1), 1995 (emphasis is mine):
[1] The example in |
This function already exists in the form |
What happens when you drop an allocator that still has memory that is being used? |
@TyOverby You will use-after-free |
I thought that is prevented by implementing |
You can either have the user own the allocator (so |
Hmm I will admit that I had not considered this drawback. I'll have to think on it. |
The associated error type seems somewhat similar to when we were considering the same thing for |
Note: discussion on IRC found that let alloc = RefCell::new(Pool::new());
let vec = Vec::with_cap_and_alloc(10, &alloc);
*alloc.get_mut() = Pool::new();
// vec is now using-after-free Several solutions can be taken to this. Off the top of my head the easiest would be a new-type wrapper over RefCell that doesn't expose |
Ability to have type erased allocators (i.e. *I'm not talking from my own experience |
I had originally thought that there would not be much demand for But @petrochenkov 's recent comment clearly indicates that there may well be demand for I'm still not entirely convinced... I would be a little disappointed if the only type of allocator error available was the zero-sized |
It would be nice to know what exactly happened/is going to happen with It seemed that after 20 years of having the allocator in the container When you don't want to pay for virtual dispatch, you can always specify a On Mon, Dec 7, 2015 at 11:17 PM, Felix S Klock II [email protected]
|
That's a cool way of doing it for a particular concrete type, but is there any way that code that was generic on any BackpressureAnother unrelated idea: It'd be good if there were some way to have backpressure between allocators. For example, if I'm implementing an allocator that provides extra functionality on top of another existing allocator, and my allocator performs caching, it would be useful if the allocator I'm wrapping could inform me if memory was getting tight so I'd know to free some of the caches I was using. One option off the top of my head would be to allow registering "low memory" callbacks that an allocator can invoke to poke downstream allocators to try freeing any memory if they can. A good example of this is in Section 3.4 of this paper. |
@joshlf |
But there's no way to specialize, right? No way to make it so that |
@joshlf I'm not too familiar with the trait specialization stuff, it might be possible. My hunch is taking advantage of it would entail a vastly different algorithm, but try it out! |
@Ericson2314 Unfortunately I think it's going to be impossible soon thanks to issue 36889. Here's a short example: https://is.gd/xgT6cG |
Make a trait that just you implement? |
I don't follow - how does that solve this? |
rust-lang/#36889 only applies to inherent impls, not trait impls. |
Hmmm interesting. Seeing as the inherent impl variant is going away, maybe the trait impl variant will soon too? Or is there a good reason to keep the trait impl variant around that doesn't apply to inherent impls? |
Maybe I'm missing something, but it looks like that doesn't work either: https://is.gd/YdiPhl |
From the appendix:
@pnkfelix, is that last equation right? An allocator can return less memory than requested? Or should the equation be |
@SimonSapin no, an allocator cannot return less memory than requested. The significance of |
@pnkfelix I see, thanks. I think it would be worth expanding the doc-comment of |
I suppose bitmap allocators (allocator that tracks allocated slots using a bitmap) do allocate slots per size class and alignment class. |
Update: RFC has been accepted:
text on master: https://github.com/rust-lang/rfcs/blob/master/text/1398-kinds-of-allocators.md
tracking issue: rust-lang/rust#32838
Tasks before FCP
Kind: Copy
, rename Kind,fn dealloc
return type, ...)&mut self
(vsself
or&self
)fn oom
API design and the associated protocolError
typefn extend_in_place
fn realloc_in_place
method (returning aResult<(), SeparateUnitError>
)fn oom
API design given that associatedError
is now goneNonZero
Layout
support zero-sized inputs (delaying all checks, if any, to the allocator itself).HashMap
,Vec
(and associated iterators)BinaryHeap
BTreeSet
BtreeMap
Vec
(signatures)LinkedList
VecDeque
HashSet
HashMap
hash::RawTable
(signatures, implementation)alloc::RawVec
(signatures, implementation)String
(or not...)Box
Rc
Arc
Summary
Add a standard allocator interface and support for user-defined allocators, with the following goals:
Regarding GC: We plan to allow future allocators to integrate themselves with a standardized reflective GC interface, but leave specification of such integration for a later RFC. (The design describes a way to add such a feature in the future while ensuring that clients do not accidentally opt-in and risk unsound behavior.)
rendered