Out-of-memory handling in alloc
customarily passes Layout
to functions like handle_alloc_error
. Layout
is also embedded in TryReserveError
's internals.
At the first glance it seems quite sensible, because Layout
is given to allocators, so OOM handlers get exactly the same information as the allocator.
However, Layout
is just size
+ align
, and I don't see any serious use-case for having align
.
-
It's not possible to use the
align
field to report an invalid alignment. It has to be valid by the contract ofLayout
. Invalidalign
values will never reach the memory allocator or the OOM handling machinery. Invalid alignment goes through different paths, and causespanic!("capacity overflow")
or aTryReserveError
with (not yet stabilized)CapacityOverflow
kind. When capacity overflow happens, you don't get any details at all. -
The
Allocator
API takes aLayout
, so any direct users of allocators already know what layout they're using. The allocator has no need to report it back, and couldn't even if it wanted, becauseAllocError
is a unit struct (which I think is good, because it keepsResult
of allocators as small as possible). -
As far as I can tell, all current valid values of the alignment are pretty boring and predictable. Collections always use
mem::align_of::<T>
.Rc
/Arc
only pad it to the alignment ofusize
. Users can easily replicate thealign
value if they really wanted to. I can imagine some more advanced collections could try to align data to cache lines or page size, but even then, what's the use-case for reporting that to the OOM handler in particular?
Users may want to track how much memory is wasted due to alignment and other reasons, but the OOM handler is unsuitable for that. It only gets a singular data point, only in exceptional circumstances. In practice, all metadata about memory usage and efficiency is better collected by wrapping the allocator, which knows the Layout
and its own internals, and can expose a custom interface for reporting as much info as desired (which jemalloc
and cap
already do).
There's an open question whether custom allocators should be returning custom errors, but Layout.align
certainly isn't it. Layout
is stable, not parametrized by an allocator, and extra info would go into its own separate type.
Hashbrown's TryReserveError
exposes the Layout
. I've searched github for uses of it, and couldn't find any uses of align
. It's common to just map it to application's own Error::OOM
.
There's unstable set_alloc_error_hook
. I've searched github for its uses. One printed {layout:?}
, and all more specific uses only looked at the layout.size()
or didn't even touch the layout
. Gecko's OOM handler only takes size. The hook is scheduled for removal to be replaced by oom=panic
.
Therefore, I suggest reporting just the size
on allocation failures in try_reserve
and OOM hook/panic. I think even size isn't strictly necessary, but it can be useful to know whether an allocation failure happened on an unrealistically-huge bigger-than-ram allocation, which suggests it's a bug in the program (e.g. a negative size) not an actual OOM situation.
This would allow TryReserveError
to be half the size. It can internally be a NonZeroUsize
(or a custom usize niche) with values > isize::MAX
meaning capacity overflow. It'd be cheap to construct (from saturating arithmetic), and it'd be small in Result<(), TryReserveError>
. Currently it's an opaque type, so its internals can be changed. There's proposed AllocErrorPanicPayload
that exposes Layout
, but that could be easily changed to return only size
.