Open nikomatsakis opened 8 years ago
I unfortunately wasn't paying close enough attention to mention this in the RFC discussion, but I think that realloc_in_place
should be replaced by two functions, grow_in_place
and shrink_in_place
, for two reasons:
realloc
or realloc_in_place
) where it is unknown whether the size of the allocation is increasing or decreasing. Using more specialized methods makes it slightly more clear what is going on.realloc_in_place
is quite small, using grow
and shrink
better captures the distinct tasks that an allocator needs to perform.Note that these can be added backwards-compatibly next to realloc_in_place
, but this would constrain which functions would be by default implemented in terms of which others.
For consistency, realloc
would probably also want to be split into grow
and split
, but the only advantage to having an overloadable realloc
function that I know of is to be able to use mmap
's remap option, which does not have such a distinction.
Additionally, I think that the default implementations of realloc
and realloc_in_place
should be slightly adjusted - instead of checking against the usable_size
, realloc
should just first try to realloc_in_place
. In turn, realloc_in_place
should by default check against the usable size and return success in the case of a small change instead of universally returning failure.
This makes it easier to produce a high-performance implementation of realloc
: all that is required is improving realloc_in_place
. However, the default performance of realloc
does not suffer, as the check against the usable_size
is still performed.
Another issue: The doc for fn realloc_in_place
says that if it returns Ok, then one is assured that ptr
now "fits" new_layout
.
To me this implies that it must check that the alignment of the given address matches any constraint implied by new_layout
.
However, I don't think the spec for the underlying fn reallocate_inplace
function implies that it will perform any such check.
fn realloc_in_place
will themselves be ensuring that the alignments work (in practice I suspect it means that the same alignment is required everywhere for the given use case...)So, should the implementation of fn realloc_in_place
really be burdened with checking that the alignment of the given ptr
is compatible with that of new_layout
? It is probably better in this case (of this one method) to push that requirement back to the caller...
@gereeter you make good points; I will add them to the check list I am accumulating in the issue description.
(at this point I am waiting for #[may_dangle]
support to ride the train into the beta
channel so that I will then be able to use it for std collections as part of allocator integration)
I'm new to Rust, so forgive me if this has been discussed elsewhere.
Is there any thought on how to support object-specific allocators? Some allocators such as slab allocators and magazine allocators are bound to a particular type, and do the work of constructing new objects, caching constructed objects which have been "freed" (rather than actually dropping them), returning already-constructed cached objects, and dropping objects before freeing the underlying memory to an underlying allocator when required.
Currently, this proposal doesn't include anything along the lines of ObjectAllocator<T>
, but it would be very helpful. In particular, I'm working on an implementation of a magazine allocator object-caching layer (link above), and while I can have this only wrap an Allocator
and do the work of constructing and dropping objects in the caching layer itself, it'd be great if I could also have this wrap other object allocators (like a slab allocator) and truly be a generic caching layer.
Where would an object allocator type or trait fit into this proposal? Would it be left for a future RFC? Something else?
I don't think this has been discussed yet.
You could write your own ObjectAllocator<T>
, and then do impl<T: Allocator, U> ObjectAllocator<U> for T { .. }
, so that every regular allocator can serve as an object-specific allocator for all objects.
Future work would be modifying collections to use your trait for their nodes, instead of plain ole' (generic) allocators directly.
@pnkfelix
(at this point I am waiting for #[may_dangle] support to ride the train into the beta channel so that I will then be able to use it for std collections as part of allocator integration)
I guess this has happened?
@Ericson2314 Yeah, writing my own is definitely an option for experimental purposes, but I think there'd be much more benefit to it being standardized in terms of interoperability (for example, I plan on also implementing a slab allocator, but it would be nice if a third-party user of my code could use somebody else's slab allocator with my magazine caching layer). My question is simply whether an ObjectAllocator<T>
trait or something like it is worth discussing. Although it seems that it might be best for a different RFC? I'm not terribly familiar with the guidelines for how much belongs in a single RFC and when things belong in separate RFCs...
@joshlf
Where would an object allocator type or trait fit into this proposal? Would it be left for a future RFC? Something else?
Yes, it would be another RFC.
I'm not terribly familiar with the guidelines for how much belongs in a single RFC and when things belong in separate RFCs...
that depends on the scope of the RFC itself, which is decided by the person who writes it, and then feedback is given by everyone.
But really, as this is a tracking issue for this already-accepted RFC, thinking about extensions and design changes isn't really for this thread; you should open a new one over on the RFCs repo.
@joshlf Ah, I thought ObjectAllocator<T>
was supposed to be a trait. I meant prototype the trait not a specific allocator. Yes that trait would merit its own RFC as @steveklabnik says.
@steveklabnik yeah now discussion would be better elsewhere. But @joshlf was also raising the issue lest it expose a hitherto unforeseen flaw in the accepted but unimplemented API design. In that sense it matches the earlier posts in this thread.
@Ericson2314 Yeah, I thought that was what you meant. I think we're on the same page :)
@steveklabnik Sounds good; I'll poke around with my own implementation and submit an RFC if it ends up seeming like a good idea.
@joshlf I don't any reason why custom allocators would go into the compiler or standard library. Once this RFC lands, you could easily publish your own crate that does an arbitrary sort of allocation (even a fully-fledged allocator like jemalloc could be custom-implemented!).
@alexreg This isn't about a particular custom allocator, but rather a trait that specifies the type of all allocators which are parametric on a particular type. So just like RFC 1398 defines a trait (Allocator
) that is the type of any low-level allocator, I'm asking about a trait (ObjectAllocator<T>
) that is the type of any allocator which can allocate/deallocate and construct/drop objects of type T
.
@alexreg See my early point about using standard library collections with custom object-specific allocators.
Sure, but I’m not sure that would belong in the standard library. Could easily go into another crate, with no loss of functionality or usability.
On 4 Jan 2017, at 21:59, Joshua Liebow-Feeser notifications@github.com wrote:
@alexreg https://github.com/alexreg This isn't about a particular custom allocator, but rather a trait that specifies the type of all allocators which are parametric on a particular type. So just like RFC 1398 defines a trait (Allocator) that is the type of any low-level allocator, I'm asking about a trait (ObjectAllocator
) that is the type of any allocator which can allocate/deallocate and construct/drop objects of type T. — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/rust-lang/rust/issues/32838#issuecomment-270499064, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEF3IhyyPhFgu1EGHr_GM_Evsr0SRzIks5rPBZGgaJpZM4IDYUN.
I think you’d want to use standard-library collections (any heap-allocated value) with an arbitrary custom allocator; i.e. not limited to object-specific ones.
On 4 Jan 2017, at 22:01, John Ericson notifications@github.com wrote:
@alexreg https://github.com/alexreg See my early point about using standard library collections with custom object-specific allocators.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/rust-lang/rust/issues/32838#issuecomment-270499628, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEF3CrjYIXqcv8Aqvb4VTyPcajJozICks5rPBbOgaJpZM4IDYUN.
Sure, but I’m not sure that would belong in the standard library. Could easily go into another crate, with no loss of functionality or usability.
Yes but you probably want some standard library functionality to rely on it (such as what @Ericson2314 suggested).
I think you’d want to use standard-library collections (any heap-allocated value) with an arbitrary custom allocator; i.e. not limited to object-specific ones.
Ideally you'd want both - to accept either type of allocator. There are very significant benefits to using object-specific caching; for example, both slab allocation and magazine caching give very significant performance benefits - take a look at the papers I linked to above if you're curious.
But the object allocator trait could simply be a subtrait of the general allocator trait. It’s as simple as that, as far as I’m concerned. Sure, certain types of allocators can be more efficient than general-purpose allocators, but neither the compiler nor the standard really need to (or indeed should) know about this.
On 4 Jan 2017, at 22:13, Joshua Liebow-Feeser notifications@github.com wrote:
Sure, but I’m not sure that would belong in the standard library. Could easily go into another crate, with no loss of functionality or usability.
Yes but you probably want some standard library functionality to rely on it (such as what @Ericson2314 https://github.com/Ericson2314 suggested).
I think you’d want to use standard-library collections (any heap-allocated value) with an arbitrary custom allocator; i.e. not limited to object-specific ones.
Ideally you'd want both - to accept either type of allocator. There are very significant benefits to using object-specific caching; for example, both slab allocation and magazine caching give very significant performance benefits - take a look at the papers I linked to above if you're curious.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/rust-lang/rust/issues/32838#issuecomment-270502231, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEF3L9F9r_0T5evOtt7Es92vw6gBxR9ks5rPBl9gaJpZM4IDYUN.
But the object allocator trait could simply be a subtrait of the general allocator trait. It’s as simple as that, as far as I’m concerned. Sure, certain types of allocators can be more efficient than general-purpose allocators, but neither the compiler nor the standard really need to (or indeed should) know about this.
Ah, so the problem is that the semantics are different. Allocator
allocates and frees raw byte blobs. ObjectAllocator<T>
, on the other hand, would allocate already-constructed objects and would also be responsible for dropping these objects (including being able to cache constructed objects which could be handed out later in leu of constructing a newly-allocated object, which is expensive). The trait would look something like this:
trait ObjectAllocator<T> {
fn alloc() -> T;
fn free(t T);
}
This is not compatible with Allocator
, whose methods deal with raw pointers and have no notion of type. Additionally, with Allocator
s, it is the caller's responsibility to drop
the object being freed first. This is really important - knowing about the type T
allows ObjectAllocator<T>
to do things like call T
's drop
method, and since free(t)
moves t
into free
, the caller cannot drop t
first - it is instead the ObjectAllocator<T>
's responsibility. Fundamentally, these two traits are incompatible with one another.
Ah right, I see. I thought this proposal already included something like that, i.e. a “higher-level” allocator over the byte level. In that case, a perfectly fair proposal!
On 4 Jan 2017, at 22:29, Joshua Liebow-Feeser notifications@github.com wrote:
But the object allocator trait could simply be a subtrait of the general allocator trait. It’s as simple as that, as far as I’m concerned. Sure, certain types of allocators can be more efficient than general-purpose allocators, but neither the compiler nor the standard really need to (or indeed should) know about this.
Ah, so the problem is that the semantics are different. Allocator allocates and frees raw byte blobs. ObjectAllocator
, on the other hand, would allocate already-constructed objects and would also be responsible for dropping these objects (including being able to cache constructed objects which could be handed out later in leu of constructing a newly-allocated object, which is expensive). The trait would look something like this: trait ObjectAllocator
{ fn alloc() -> T; fn free(t T); } This is not compatible with Allocator, whose methods deal with raw pointers and have no notion of type. Additionally, with Allocators, it is the caller's responsibility to drop the object being freed first. This is really important - knowing about the type T allows ObjectAllocator to do things like call T's drop method, and since free(t) moves t into free, the caller cannot drop t first - it is instead the ObjectAllocator 's responsibility. Fundamentally, these two traits are incompatible with one another. — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/rust-lang/rust/issues/32838#issuecomment-270505704, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEF3GViJBefuk8IWgPauPyL5tV78Fn5ks5rPB08gaJpZM4IDYUN.
@alexreg Ah yes, I was hoping so too :) Oh well - it'll have to wait for another RFC.
Yes, do kick start that RFC, I’m sure it would get plenty of support! And thanks for the clarification (I hadn’t kept up with the details of this RFC at all).
On 5 Jan 2017, at 00:53, Joshua Liebow-Feeser notifications@github.com wrote:
@alexreg https://github.com/alexreg Ah yes, I was hoping so too :) Oh well - it'll have to wait for another RFC.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/rust-lang/rust/issues/32838#issuecomment-270531535, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEF3MQQeXhTliU5CBsoheBFL26Ee9WUks5rPD8RgaJpZM4IDYUN.
A crate for testing custom allocators would be useful.
Forgive me if I'm missing something obvious, but is there a reason for the Layout
trait described in this RFC not to implement Copy
as well as Clone
, since it's just POD?
I can't think of any.
Sorry to be bringing this up so late in the process, but...
Might it be worth adding support for a dealloc
-like function that isn't a method, but rather a function? The idea would be to use alignment to be able to infer from a pointer where in memory its parent allocator is and thus be able to free without needing an explicit allocator reference.
This could be a big win for data structures that use custom allocators. This would allow them to not keep a reference to the allocator itself, but rather only need to be parametric on the type of the allocator to be able to call the right dealloc
function. For example, if Box
is eventually modified to support custom allocators, then it'd be able to keep being only a single word (just the pointer) as opposed to having to be expanded to two words to store a reference to the allocator as well.
On a related note, it might also be useful to support a non-method alloc
function to allow for global allocators. This would compose nicely with a non-method dealloc
function - for global allocators, there'd be no need to do any kind of pointer-to-allocator inference since there'd only be a single static instance of the allocator for the whole program.
@joshlf The current design allows you to get that by just having your allocator be a (zero-sized) unit type - i.e. struct MyAlloc;
that you then implement the Allocator
trait on.
Storing references or nothing at all, always, is less general than storing the allocator by-value.
I could see that being true for a directly-embedded type, but what about if a data structure decies to keep a reference instead? Does a reference to a zero-sized type take up zero space? That is, if I have:
struct Foo()
struct Blah{
foo: &Foo,
}
Does Blah
have zero size?
Actually, even it's possible, you might not want your allocator to have zero size. For example, you might have an allocator with a non-zero size that you allocate from, but that has the ability to free objects w/o knowing about the original allocator. This would still be useful for making a Box
take only a word. You'd have something like Box::new_from_allocator
which would have to take an allocator as an argument - and it might be a nonzero-sized allocator - but if the allocator supported freeing without the original allocator reference, the returned Box<T>
could avoid storing a reference to the allocator that was passed in the original Box::new_from_allocator
call.
For example, you might have an allocator with a non-zero size that you allocate from, but that has the ability to free objects w/o knowing about the original allocator.
I recall long, long, ago proposing factoring out separate allocator and deallocator traits (with associate types connecting the two) for basically this reason.
Is/should the compiler be allowed to optimize away allocations with these allocators?
Is/should the compiler be allowed to optimize away allocations with these allocators?
@Zoxc What do you mean?
I recall long, long, ago proposing factoring out separate allocator and deallocator traits (with associate types connecting the two) for basically this reason.
For posterity, let me clarify this statement (I talked to @Ericson2314 about it offline): The idea is that a Box
could be parametric just on a deallocator. So you could have the following implementation:
trait Allocator {
type D: Deallocator;
fn get_deallocator(&self) -> Self::D;
}
trait Deallocator {}
struct Box<T, D: Deallocator> {
ptr: *mut T,
d: D,
}
impl<T, D: Deallocator> Box<T, D> {
fn new_from_allocator<A: Allocator>(x: T, a: A) -> Box<T, A::D> {
...
Box {
ptr: ptr,
d: a.get_deallocator()
}
}
}
This way, when calling new_from_allocator
, if A::D
is a zero-sized type, then the d
field of Box<T, A::D>
takes up zero size, and so the size of the resulting Box<T, A::D>
is a single word.
Is there a timeline for when this will land? I'm working on some allocator stuff, and it'd be nice if this stuff were there for me to build off of.
If there's interest, I'd be happy to lend some cycles to this, but I'm relatively new to Rust, so that might just create more work for the maintainers in terms of having to code review a newbie's code. I don't want to step on anybody's toes, and I don't want to make more work for people.
Ok we've recently met to evaluate the state of allocators and I think there's some good news for this as well! It looks like support has not yet landed in libstd for these APIs, but everyone's still happy with them landing at any time!
One thing we discussed is that changing over all the libstd types may be a bit premature due to possible inference issues, but regardless of that it seems like a good idea to land the Allocator
trait and the Layout
type in the proposed std::heap
module for experimentation elsewhere in the ecosystem!
@joshlf if you'd like to help out here I think that'd be more than welcome! The first piece will likely be landing the basic type/trait from this RFC into the standard library, and then from there we can start experimenting and playing around with collections in libstd as well.
@alexcrichton I think your link is broken? It points back here.
One thing we discussed is that changing over all the libstd types may be a bit premature due to possible inference issues
Adding the trait is a good first step, but without refactoring existing APIs to use it they won't see much usage. In https://github.com/rust-lang/rust/issues/27336#issuecomment-300721558 I propose we can refactor the crates behind the facade immediately, but add newtype wrappers in std
. Annoying to do, but allows us to make progress.
@alexcrichton What would be the process for getting object allocators in? My experiments so far (soon to be public; I can add you to the private GH repo if you're curious) and the discussion here have led me to believe that there's going to be a near-perfect symmetry between the allocator traits and object allocator traits. E.g., you'll have something like (I changed Address
to *mut u8
for symmetry with *mut T
from ObjectAllocator<T>
; we'd probably end up with Address<T>
or something like that):
unsafe trait Allocator {
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>;
unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout);
}
unsafe trait ObjectAllocator<T> {
unsafe fn alloc(&mut self) -> Result<*mut T, AllocErr>;
unsafe fn dealloc(&mut self, ptr: *mut T);
}
Thus, I think experimenting with both allocators and object allocators at the same time could be useful. I'm not sure if this is the right place for that, though, or whether there should be another RFC or, at the very least, a separate PR.
Oh I meant to link here which also has information about the global allocator. @joshlf is that what you're thinking?
It sounds like @alexcrichton wants a PR that provides the Allocator
trait and Layout
type, even if its not integrated into any collection in libstd
.
If I understand that correctly, then I can put up a PR for that. I had not done so because I keep trying to get at least integration with RawVec
and Vec
prototyped. (At this point I have RawVec
done, but Vec
is a bit more challenging due to the many other structures that build off of it, like Drain
and IntoIter
etc...)
actually, my current branch seems like it might actually build (and the one test for integration withRawVec
passed), so I went ahead and posted it: #42313
@hawkw asked:
Forgive me if I'm missing something obvious, but is there a reason for the Layout trait described in this RFC not to implement Copy as well as Clone, since it's just POD?
The reason I made Layout
only implement Clone
and not Copy
is that I wanted to leave open the possibility of adding more structure to the Layout
type. In particular, I still am interested in trying to have the Layout
attempt to track any type structure used to construct it (e.g. 16-array of struct { x: u8, y: [char; 215] }
), so that allocators would have the option of exposing instrumentation routines that report on what types their current contents are composes from.
This would almost certainly have to be an optional feature, i.e. it seems like the tide is firmly against forcing developers to to use the type-enriched Layout
constructors. so any instrumentation of this form would need to include something like an "unknown memory blocks" category to handle allocations that do not have the type information.
But nonetheless, features like this were the main reason why I did not opt to make Layout
implement Copy
; I basically figured that an implementation of Copy
would be a premature constraint on Layout
itself.
@alexcrichton @pnkfelix
Looks like @pnkfelix has this one covered, and that PR is getting traction, so let's just go with that. I'm looking over it and making comments now, and it looks great!
Currently the signature for Allocator::oom
is:
fn oom(&mut self, _: AllocErr) -> ! {
unsafe { ::core::intrinsics::abort() }
}
It was brought to my attention, though, that Gecko at least likes to know the allocation size as well on OOM. We may wish to consider this when stabilizing to perhaps add context like Option<Layout>
for why OOM is happening.
@alexcrichton
Might it be worth having either multiple oom_xxx
variants or an enum of different argument types? There are a couple of different signatures for methods that could fail (e.g., alloc
takes a layout, realloc
takes a pointer, an original layout, and a new layout, etc), and there might be cases in which an oom
-like method would want to know about all of them.
@joshlf that's true, yes, but I'm not sure if it's useful. I wouldn't want to just add features because we can, they should continue to be well motivated.
A point for stabilization here is also "determine what the requirements are on the alignment provided to fn dealloc
", and the current implementation of dealloc
on Windows uses align
to determine how to correctly free. @ruuda you may be interested in this fact.
A point for stabilization here is also "determine what the requirements are on the alignment provided to
fn dealloc
", and the current implementation ofdealloc
on Windows usesalign
to determine how to correctly free.
Yes, I think this is how I initially ran into this; my program crashed on Windows because of this. As HeapAlloc
makes no alignment guarantees, allocate
allocates a bigger region and stores the original pointer in a header, but as an optimization this is avoided if the alignment requirements would be satisfied anyway. I wonder if there is a way to convert HeapAlloc
into an alignment-aware allocator that does not require alignment on free, without losing this optimization.
@ruuda
As
HeapAlloc
makes no alignment guarantees
It does provide a minimum alignment guarantee of 8 bytes for 32bit or 16 bytes for 64bit, it just doesn't provide any way to guarantee alignment higher than that.
The _aligned_malloc
provided by the CRT on Windows can provide allocations of higher alignment, but notably it must be paired with _aligned_free
, using free
is illegal. So if you don't know whether an allocation was done via malloc
or _aligned_malloc
then you're stuck in the same conundrum that alloc_system
is in on Windows if you don't know the alignment for deallocate
. The CRT does not provide the standard aligned_alloc
function which can be paired with free
, so even Microsoft hasn't been able to solve this problem. (Although it is a C11 function and Microsoft doesn't support C11 so that's a weak argument.)
Do note that deallocate
only cares about the alignment to know whether it is overaligned, the actual value itself is irrelevant. If you wanted a deallocate
that was truly alignment independent, you could simply treat all allocations as overaligned, but you'd waste a lot of memory on small allocations.
@alexcrichton wrote:
Currently the signature for
Allocator::oom
is:fn oom(&mut self, _: AllocErr) -> ! { unsafe { ::core::intrinsics::abort() } }
It was brought to my attention, though, that Gecko at least likes to know the allocation size as well on OOM. We may wish to consider this when stabilizing to perhaps add context like
Option<Layout>
for why OOM is happening.
The AllocErr
already carries the Layout
in the AllocErr::Exhausted
variant. We could just add the Layout
to the AllocErr::Unsupported
variant as well, which I think would be simplest in terms of client expectations. (It does have the drawback of silghtly increasing the side of the AllocErr
enum itself, but maybe we shouldn't worry about that...)
Oh I suspect that's all that's needed, thanks for the correction @pnkfelix!
I'm going to start repurposing this issue for the tracking issue for std::heap
in general as it will be after https://github.com/rust-lang/rust/pull/42727 lands. I'll be closing a few other related issues in favor of this.
📢 This feature has a dedicated working group, please direct comments and concerns to the working group's repo.
The remainder of this post is no longer an accurate summary of the current state; see that dedicated working group instead.
Old content
Original Post: ----- FCP proposal: https://github.com/rust-lang/rust/issues/32838#issuecomment-336957415 FCP checkboxes: https://github.com/rust-lang/rust/issues/32838#issuecomment-336980230 --- Tracking issue for rust-lang/rfcs#1398 and the `std::heap` module. - [x] land `struct Layout`, `trait Allocator`, and default implementations in `alloc` crate (https://github.com/rust-lang/rust/pull/42313) - [x] decide where parts should live (e.g. default impls has dependency on `alloc` crate, but `Layout`/`Allocator` _could_ be in `libcore`...) (https://github.com/rust-lang/rust/pull/42313) - [ ] fixme from source code: audit default implementations (in `Layout` for overflow errors, (potentially switching to overflowing_add and overflowing_mul as necessary). - [x] decide if `realloc_in_place` should be replaced with `grow_in_place` and `shrink_in_place` ([comment](https://github.com/rust-lang/rust/issues/32838#issuecomment-208141759)) (https://github.com/rust-lang/rust/pull/42313) - [ ] review arguments for/against associated error type (see subthread [here](https://github.com/rust-lang/rfcs/pull/1398#issuecomment-204561446)) - [ ] determine what the requirements are on the alignment provided to `fn dealloc`. (See discussion on [allocator rfc](https://github.com/rust-lang/rfcs/pull/1398#issuecomment-198584430) and [global allocator rfc](https://github.com/rust-lang/rfcs/pull/1974#issuecomment-302789872) and [trait `Alloc` PR](https://github.com/rust-lang/rust/pull/42313#issuecomment-306202489).) * Is it required to deallocate with the exact `align` that you allocate with? [Concerns have been raised](https://github.com/rust-lang/rfcs/pull/1974#issuecomment-302789872) that allocators like jemalloc don't require this, and it's difficult to envision an allocator that does require this. ([more discussion](https://github.com/rust-lang/rfcs/pull/1398#issuecomment-198584430)). @ruuda and @rkruppe look like they've got the most thoughts so far on this. - [ ] should `AllocErr` be `Error` instead? ([comment](https://github.com/rust-lang/rust/pull/42313#discussion_r122580471)) - [x] Is it required to deallocate with the *exact* size that you allocate with? With the `usable_size` business we may wish to allow, for example, that you if you allocate with `(size, align)` you must deallocate with a size somewhere in the range of `size...usable_size(size, align)`. It appears that jemalloc is totally ok with this (doesn't require you to deallocate with a *precise* `size` you allocate with) and this would also allow `Vec` to naturally take advantage of the excess capacity jemalloc gives it when it does an allocation. (although actually doing this is also somewhat orthogonal to this decision, we're just empowering `Vec`). So far @Gankro has most of the thoughts on this. (@alexcrichton believes this was settled in https://github.com/rust-lang/rust/pull/42313 due to the definition of "fits") - [ ] similar to previous question: Is it required to deallocate with the *exact* alignment that you allocated with? (See comment from [5 June 2017](https://github.com/rust-lang/rust/pull/42313#issuecomment-306202489)) - [x] OSX/`alloc_system` is buggy on *huge* alignments (e.g. an align of `1 << 32`) https://github.com/rust-lang/rust/issues/30170 #43217 - [ ] should `Layout` provide a `fn stride(&self)` method? (See also https://github.com/rust-lang/rfcs/issues/1397, https://github.com/rust-lang/rust/issues/17027 ) - [x] `Allocator::owns` as a method? https://github.com/rust-lang/rust/issues/44302 State of `std::heap` after https://github.com/rust-lang/rust/pull/42313: ```rust pub struct Layout { /* ... */ } impl Layout { pub fn new