基于 rust-lang/rust 源码深度解析
2026-03-12 | 技术深度解读
Layout:描述一块内存的最小 size / align 需求LayoutError:所有非法组合统一错误mod.rs:定义 Allocator trait,消费 Layoutglobal.rs:全局分配 API 的更高层包装const fn、小函数、unchecked intrinsics// Seemingly inconsequential code changes to this file can lead to measurable
// performance impact on compilation times, due at least in part to the fact
// that the layout code gets called from many instantiations of the various
// collections, resulting in having to optimize down excess IR multiple times.
// Your performance intuition is useless. Run perf.
size: usizealign: Alignmentusize 对齐值,而是更强约束的 Alignment 类型。/// (Note that layouts are *not* required to have non-zero size,
/// even though `GlobalAlloc` requires that all memory requests
/// be non-zero in size. A caller must either ensure that conditions
/// like this are met, use specific allocators with looser
/// requirements, or use the more lenient `Allocator` interface.)
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[lang = "alloc_layout"]
pub struct Layout {
// size of the requested block of memory, measured in bytes.
size: usize,
// alignment of the requested block of memory, measured in bytes.
// we ensure that this is always a power-of-two, because API's
// like `posix_memalign` require it and it is a reasonable
// constraint to impose on Layout constructors.
//
// (However, we do not analogously require `align >= sizeof(void*)`,
// even though that is *also* a requirement of `posix_memalign`.)
isize 表示距离isize::MAX,一些合法 API 无法安全表达LayoutLayoutError /// * `size`, when rounded up to the nearest multiple of `align`,
/// must not overflow `isize` (i.e., the rounded value must be
/// less than or equal to `isize::MAX`).
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")]
#[inline]
pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutError> {
if Layout::is_size_align_valid(size, align) {
// SAFETY: Layout::is_size_align_valid checks the preconditions for this call.
unsafe { Ok(Layout { size, align: mem::transmute(align) }) }
is_size_align_valid(size, align)Alignment::newis_size_alignment_valid(size, alignment) Err(LayoutError)
}
}
#[inline]
const fn is_size_align_valid(size: usize, align: usize) -> bool {
let Some(alignment) = Alignment::new(align) else { return false };
Self::is_size_alignment_valid(size, alignment)
}
isize::MAX + 1 - align const fn is_size_alignment_valid(size: usize, alignment: Alignment) -> bool {
size <= Self::max_size_for_alignment(alignment)
}
#[inline(always)]
const fn max_size_for_alignment(alignment: Alignment) -> usize {
// (power-of-two implies align != 0.)
// Rounded up size is:
// size_rounded_up = (size + align - 1) & !(align - 1);
//
// We know from above that align != 0. If adding (align - 1)
// does not overflow, then rounding up will be fine.
//
// Conversely, &-masking with !(align - 1) will subtract off
// only low-order-bits. Thus if overflow occurs with the sum,
// the &-mask cannot subtract enough to undo that overflow.
//
// Above implies that checking for summation overflow is both
// necessary and sufficient.
// SAFETY: the maximum possible alignment is `isize::MAX + 1`,
(size + align - 1) & !(align - 1)size + align - 1 本身不溢出,则掩码只会减小结果unchecked_add / unchecked_sub / unchecked_mulassert_unsafe_precondition! 记录 unsafe 契约 /// Creates a layout, bypassing all checks.
///
/// # Safety
///
/// This function is unsafe as it does not verify the preconditions from
/// [`Layout::from_size_align`].
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[rustc_const_stable(feature = "const_alloc_layout_unchecked", since = "1.36.0")]
#[must_use]
#[inline]
#[track_caller]
pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
assert_unsafe_precondition!(
check_library_ub,
"Layout::from_size_align_unchecked requires that align is a power of 2 \
and the rounded-up allocation size does not exceed isize::MAX",
(
size: usize = size,
align: usize = align,
) => Layout::is_size_align_valid(size, align)
);
// SAFETY: the caller is required to uphold the preconditions.
size() 直接返回字节数align() 返回最小对齐 }
/// The minimum size in bytes for a memory block of this layout.
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")]
#[must_use]
#[inline]
pub const fn size(&self) -> usize {
self.size
}
/// The minimum byte alignment for a memory block of this layout.
///
/// The returned alignment is guaranteed to be a power of two.
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")]
#[must_use = "this returns the minimum alignment, \
without modifying the layout"]
#[inline]
pub const fn align(&self) -> usize {
self.align.as_usize()
}
/// The minimum byte alignment for a memory block of this layout.
///
/// The returned alignment is guaranteed to be a power of two.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[must_use = "this returns the minimum alignment, without modifying the layout"]
#[inline]
pub const fn alignment(&self) -> Alignment {
self.align
SizedTypeProperties::LAYOUT
/// Constructs a `Layout` suitable for holding a value of type `T`.
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[rustc_const_stable(feature = "alloc_layout_const_new", since = "1.42.0")]
#[must_use]
#[inline]
pub const fn new<T>() -> Self {
<T as SizedTypeProperties>::LAYOUT
for_value(&T) 支持 slice / trait object 等动态大小类型size_of_val 与 Alignment::of_val 读取胖指针元数据
/// Produces layout describing a record that could be used to
/// allocate backing structure for `T` (which could be a trait
/// or other unsized type like a slice).
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
#[must_use]
#[inline]
pub const fn for_value<T: ?Sized>(t: &T) -> Self {
let (size, alignment) = (size_of_val(t), Alignment::of_val(t));
// SAFETY: see rationale in `new` for why this is using the unsafe variant
unsafe { Layout::from_size_alignment_unchecked(size, alignment) }
///
/// # Safety
///
/// This function is only safe to call if the following conditions hold:
///
/// - If `T` is `Sized`, this function is always safe to call.
/// - If the unsized tail of `T` is:
/// - a [slice], then the length of the slice tail must be an initialized
/// integer, and the size of the *entire value*
/// (dynamic tail length + statically sized prefix) must fit in `isize`.
/// For the special case where the dynamic tail length is 0, this function
/// is safe to call.
/// - a [trait object], then the vtable part of the pointer must point
/// to a valid vtable for the type `T` acquired by an unsizing coercion,
/// and the size of the *entire value*
/// (dynamic tail length + statically sized prefix) must fit in `isize`.
/// - an (unstable) [extern type], then this function is always safe to
/// call, but may panic or otherwise return the wrong value, as the
/// extern type's layout is not known. This is the same behavior as
/// [`Layout::for_value`] on a reference to an extern type tail.
/// - otherwise, it is conservatively not allowed to call this function.
///
/// [trait object]: ../../book/ch17-02-trait-objects.html
/// [extern type]: ../../unstable-book/language-features/extern-types.html
#[unstable(feature = "layout_for_ptr", issue = "69835")]
#[must_use]
#[inline]
pub const unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self {
// SAFETY: we pass along the prerequisites of these functions to the caller
let (size, alignment) = unsafe { (mem::size_of_val_raw(t), Alignment::of_val_raw(t)) };
// SAFETY: see rationale in `new` for why this is using the unsafe variant
unsafe { Layout::from_size_alignment_unchecked(size, alignment) }
}
/// Creates a `NonNull` that is dangling, but well-aligned for this Layout.
///
/// Note that the address of the returned pointer may potentially
/// as a "not yet initialized" sentinel value.
/// Types that lazily allocate must track initialization by some other means.
#[stable(feature = "alloc_layout_extra", since = "1.95.0")]
#[rustc_const_stable(feature = "alloc_layout_extra", since = "1.95.0")]
#[must_use]
#[inline]
pub const fn dangling_ptr(&self) -> NonNull<u8> {
NonNull::without_provenance(self.align.as_nonzero())
}
/// Creates a layout describing the record that can hold a value
/// of the same layout as `self`, but that also is aligned to
/// alignment `align` (measured in bytes).
/// If `self` already meets the prescribed alignment, then returns
/// `self`.
///
/// Note that this method does not add any padding to the overall
/// size, regardless of whether the returned layout has a different
/// alignment. In other words, if `K` has size 16, `K.align_to(32)`
/// will *still* have size 16.
///
/// Returns an error if the combination of `self.size()` and the given
/// `align` violates the conditions listed in [`Layout::from_size_align`].
#[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
#[inline]
pub const fn align_to(&self, align: usize) -> Result<Self, LayoutError> {
if let Some(alignment) = Alignment::new(align) {
self.adjust_alignment_to(alignment)
} else {
Err(LayoutError)
}
}
/// Creates a layout describing the record that can hold a value
/// of the same layout as `self`, but that also is aligned to
/// alignment `alignment`.
///
/// If `self` already meets the prescribed alignment, then returns
/// `self`.
///
/// Note that this method does not add any padding to the overall
/// size, regardless of whether the returned layout has a different
/// alignment. In other words, if `K` has size 16, `K.align_to(32)`
/// will *still* have size 16.
///
/// Returns an error if the combination of `self.size()` and the given
/// `alignment` violates the conditions listed in [`Layout::from_size_alignment`].
#[inline]
pub const fn adjust_alignment_to(&self, alignment: Alignment) -> Result<Self, LayoutError> {
Layout::from_size_alignment(self.size, Alignment::max(self.align, alignment))
}
/// Returns the amount of padding we must insert after `self`
/// to ensure that the following address will satisfy `alignment`.
///
/// e.g., if `self.size()` is 9, then `self.padding_needed_for(alignment4)`
/// (where `alignment4.as_usize() == 4`)
/// returns 3, because that is the minimum number of bytes of
/// padding required to get a 4-aligned address (assuming that the
/// corresponding memory block starts at a 4-aligned address).
///
/// Note that the utility of the returned value requires `alignment`
/// to be less than or equal to the alignment of the starting
/// address for the whole allocated block of memory. One way to
/// satisfy this constraint is to ensure `alignment.as_usize() <= self.align()`.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[must_use = "this returns the padding needed, without modifying the `Layout`"]
#[inline]
(size + align - 1) & !(align - 1)Alignment 类型,让公式随处可用 let len_rounded_up = self.size_rounded_up_to_custom_alignment(alignment);
// SAFETY: Cannot overflow because the rounded-up value is never less
unsafe { unchecked_sub(len_rounded_up, self.size) }
}
/// Returns the smallest multiple of `align` greater than or equal to `self.size()`.
///
/// This can return at most `Alignment::MAX` (aka `isize::MAX + 1`)
/// because the original size is at most `isize::MAX`.
#[inline]
const fn size_rounded_up_to_custom_alignment(&self, alignment: Alignment) -> usize {
// SAFETY:
// Rounded up value is:
// size_rounded_up = (size + align - 1) & !(align - 1);
//
// The arithmetic we do here can never overflow:
//
// 1. align is guaranteed to be > 0, so align - 1 is always
// valid.
//
// 2. size is at most `isize::MAX`, so adding `align - 1` (which is at
// most `isize::MAX`) can never overflow a `usize`.
//
// 3. masking by the alignment can remove at most `align - 1`,
// which is what we just added, thus the value we return is never
repr(C) 最终大小时常见的“收尾动作” //
// (Size 0 Align MAX is already aligned, so stays the same, but things like
// Size 1 Align MAX or Size isize::MAX Align 2 round up to `isize::MAX + 1`.)
unsafe {
let align_m1 = unchecked_sub(alignment.as_usize(), 1);
unchecked_add(self.size, align_m1) & !align_m1
}
}
/// Creates a layout by rounding the size of this layout up to a multiple
/// of the layout's alignment.
///
/// This is equivalent to adding the result of `padding_needed_for`
/// to the layout's current size.
#[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
#[must_use = "this returns a new `Layout`, \
without modifying the original"]
repeat(n) 返回 (layout, stride)pad_to_align,再重复,再把最后一个元素接回去 pub const fn pad_to_align(&self) -> Layout {
// This cannot overflow. Quoting from the invariant of Layout:
// > `size`, when rounded up to the nearest multiple of `align`,
// > must not overflow isize (i.e., the rounded value must be
// > less than or equal to `isize::MAX`)
let new_size = self.size_rounded_up_to_custom_alignment(self.align);
// SAFETY: padded size is guaranteed to not exceed `isize::MAX`.
unsafe { Layout::from_size_alignment_unchecked(new_size, self.alignment()) }
}
/// Creates a layout describing the record for `n` instances of
/// `self`, with a suitable amount of padding between each to
/// ensure that each instance is given its requested size and
/// alignment. On success, returns `(k, offs)` where `k` is the
/// layout of the array and `offs` is the distance between the start
/// of each element in the array.
///
/// Does not include padding after the trailing element.
///
/// (That distance between elements is sometimes known as "stride".)
///
/// On arithmetic overflow, returns `LayoutError`.
///
/// # Examples
///
/// ```
/// use std::alloc::Layout;
///
/// // All rust types have a size that's a multiple of their alignment.
/// let normal = Layout::from_size_align(12, 4).unwrap();
/// let repeated = normal.repeat(3).unwrap();
/// assert_eq!(repeated, (Layout::from_size_align(36, 4).unwrap(), 12));
///
/// // But you can manually make layouts which don't meet that rule.
/// let padding_needed = Layout::from_size_align(6, 4).unwrap();
/// let repeated = padding_needed.repeat(3).unwrap();
/// assert_eq!(repeated, (Layout::from_size_align(22, 4).unwrap(), 8));
///
/// // Repeating an element zero times has zero size, but keeps the alignment (like `[T; 0]`)
/// let repeated = normal.repeat(0).unwrap();
/// assert_eq!(repeated, (Layout::from_size_align(0, 4).unwrap(), 12));
/// let repeated = padding_needed.repeat(0).unwrap();
/// assert_eq!(repeated, (Layout::from_size_align(0, 4).unwrap(), 8));
/// ```
#[stable(feature = "alloc_layout_extra", since = "1.95.0")]
#[rustc_const_stable(feature = "alloc_layout_extra", since = "1.95.0")]
extend(next) 计算“当前字段后接下一个字段”的新布局 pub const fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutError> {
// FIXME(const-hack): the following could be way shorter with `?`
let padded = self.pad_to_align();
let Ok(result) = (if let Some(k) = n.checked_sub(1) {
let Ok(repeated) = padded.repeat_packed(k) else {
return Err(LayoutError);
};
repeated.extend_packed(*self)
} else {
debug_assert!(n == 0);
self.repeat_packed(0)
}) else {
return Err(LayoutError);
};
Ok((result, padded.size()))
}
/// Creates a layout describing the record for `self` followed by
/// `next`, including any necessary padding to ensure that `next`
/// will be properly aligned, but *no trailing padding*.
///
/// In order to match C representation layout `repr(C)`, you should
/// call `pad_to_align` after extending the layout with all fields.
/// (There is no way to match the default Rust representation
/// layout `repr(Rust)`, as it is unspecified.)
///
/// Note that the alignment of the resulting layout will be the maximum of
/// those of `self` and `next`, in order to ensure alignment of both parts.
///
/// Returns `Ok((k, offset))`, where `k` is layout of the concatenated
/// record and `offset` is the relative location, in bytes, of the
/// start of the `next` embedded within the concatenated record
/// (assuming that the record itself starts at offset 0).
///
/// On arithmetic overflow, returns `LayoutError`.
///
/// # Examples
///
/// To calculate the layout of a `#[repr(C)]` structure and the offsets of
/// the fields from its fields' layouts:
///
/// ```rust
/// # use std::alloc::{Layout, LayoutError};
/// pub fn repr_c(fields: &[Layout]) -> Result<(Layout, Vec<usize>), LayoutError> {
/// let mut offsets = Vec::new();
/// let mut layout = Layout::from_size_align(0, 1)?;
/// for &field in fields {
/// let (new_layout, offset) = layout.extend(field)?;
/// layout = new_layout;
/// offsets.push(offset);
/// }
/// // Remember to finalize with `pad_to_align`!
/// Ok((layout.pad_to_align(), offsets))
/// }
/// # // test that it works
/// # #[repr(C)] struct S { a: u64, b: u32, c: u16, d: u32 }
/// # let s = Layout::new::<S>();
/// # let u16 = Layout::new::<u16>();
/// # let u32 = Layout::new::<u32>();
/// # let u64 = Layout::new::<u64>();
/// # assert_eq!(repr_c(&[u64, u32, u16, u32]), Ok((s, vec![0, 8, 12, 16])));
}
}
/// Creates a layout describing the record for `self` followed by
/// `next` with no additional padding between the two. Since no
/// padding is inserted, the alignment of `next` is irrelevant,
/// and is not incorporated *at all* into the resulting layout.
///
/// On arithmetic overflow, returns `LayoutError`.
#[stable(feature = "alloc_layout_extra", since = "1.95.0")]
#[rustc_const_stable(feature = "alloc_layout_extra", since = "1.95.0")]
#[inline]
pub const fn extend_packed(&self, next: Self) -> Result<Self, LayoutError> {
// SAFETY: each `size` is at most `isize::MAX == usize::MAX/2`, so the
// sum is at most `usize::MAX/2*2 == usize::MAX - 1`, and cannot overflow.
let new_size = unsafe { unchecked_add(self.size, next.size) };
repeat 相比,它不保证每个元素都对齐[T; n] 的物理内存布局 /// aligned.
///
/// On arithmetic overflow, returns `LayoutError`.
#[stable(feature = "alloc_layout_extra", since = "1.95.0")]
#[rustc_const_stable(feature = "alloc_layout_extra", since = "1.95.0")]
#[inline]
pub const fn repeat_packed(&self, n: usize) -> Result<Self, LayoutError> {
if let Some(size) = self.size.checked_mul(n) {
// The safe constructor is called here to enforce the isize size limit.
Layout::from_size_alignment(size, self.align)
} else {
Err(LayoutError)
[T; n] 布局usize 溢出与 isize 上限inner,减少每个 T 的单态化代码量 Layout::from_size_alignment(new_size, self.align)
}
/// Creates a layout describing the record for a `[T; n]`.
///
/// On arithmetic overflow or when the total size would exceed
/// `isize::MAX`, returns `LayoutError`.
#[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
#[inline]
pub const fn array<T>(n: usize) -> Result<Self, LayoutError> {
// Reduce the amount of code we need to monomorphize per `T`.
return inner(T::LAYOUT, n);
#[inline]
const fn inner(element_layout: Layout, n: usize) -> Result<Layout, LayoutError> {
let Layout { size: element_size, align: alignment } = element_layout;
// We need to check two things about the size:
// - That the total size won't overflow a `usize`, and
// - That the total size still fits in an `isize`.
// By using division we can check them both with a single threshold.
// That'd usually be a bad idea, but thankfully here the element size
// and alignment are constants, so the compiler will fold all of it.
if element_size != 0 && n > Layout::max_size_for_alignment(alignment) / element_size {
return Err(LayoutError);
}
// SAFETY: We just checked that we won't overflow `usize` when we multiply.
// This is a useless hint inside this function, but after inlining this helps
// deduplicate checks for whether the overall capacity is zero (e.g., in RawVec's
// allocation path) before/after this multiplication.
let array_size = unsafe { unchecked_mul(element_size, n) };
// SAFETY: We just checked above that the `array_size` will not
// exceed `isize::MAX` even when rounded up to the alignment.
// And `Alignment` guarantees it's a power of two.
unsafe { Ok(Layout::from_size_alignment_unchecked(array_size, alignment)) }
}
if n > max_size_for_alignment(alignment) / element_size
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[deprecated(
since = "1.52.0",
note = "Name does not follow std convention, use LayoutError",
suggestion = "LayoutError"
)]
pub type LayoutErr = LayoutError;
/// The `LayoutError` is returned when the parameters given
/// to `Layout::from_size_align`
/// or some other `Layout` constructor
/// do not satisfy its documented constraints.
#[stable(feature = "alloc_layout_error", since = "1.50.0")]
#[non_exhaustive]
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct LayoutError;
#[stable(feature = "alloc_layout", since = "1.28.0")]
impl Error for LayoutError {}
// (we need this for downstream impl of trait Error)
#[stable(feature = "alloc_layout", since = "1.28.0")]
impl fmt::Display for LayoutError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("invalid parameters to Layout::from_size_align")
}
}
Allocator::allocate(&self, layout: Layout) 等 API 全都以 Layout 为输入。///
/// # Safety
///
/// Memory blocks that are [*currently allocated*] by an allocator,
/// must point to valid memory, and retain their validity until either:
/// - the memory block is deallocated, or
/// - the allocator is dropped.
///
/// Copying, cloning, or moving the allocator must not invalidate memory blocks returned from it.
/// A copied or cloned allocator must behave like the original allocator.
///
/// A memory block which is [*currently allocated*] may be passed to
/// any method of the allocator that accepts such an argument.
///
/// [*currently allocated*]: #currently-allocated-memory
#[unstable(feature = "allocator_api", issue = "32838")]
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
pub const unsafe trait Allocator {
/// Attempts to allocate a block of memory.
///
/// On success, returns a [`NonNull<[u8]>`][NonNull] meeting the size and alignment guarantees of `layout`.
///
/// The returned block may have a larger size than specified by `layout.size()`, and may or may
/// not have its contents initialized.
///
/// The returned block of memory remains valid as long as it is [*currently allocated*] and the shorter of:
/// - the borrow-checker lifetime of the allocator type itself.
/// - as long as the allocator and all its clones have not been dropped.
///
/// [*currently allocated*]: #currently-allocated-memory
///
/// # Errors
///
/// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
/// allocator's size or alignment constraints.
///
/// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
/// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
/// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
///
/// Clients wishing to abort computation in response to an allocation error are encouraged to
/// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
///
/// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>;
/// Behaves like `allocate`, but also ensures that the returned memory is zero-initialized.
///
/// # Errors
///
/// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
/// allocator's size or alignment constraints.
///
/// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
/// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
/// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
///
/// Clients wishing to abort computation in response to an allocation error are encouraged to
/// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
///
/// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
alloc / dealloc / realloc 等接口最终仍收敛到 Layoutuse crate::alloc::Layout;
use crate::{cmp, ptr};
/// A memory allocator that can be registered as the standard library’s default
/// through the `#[global_allocator]` attribute.
///
/// Some of the methods require that a memory block be *currently
/// allocated* via an allocator. This means that:
///
/// * the starting address for that memory block was previously
/// returned by a previous call to an allocation method
/// such as `alloc`, and
///
/// * the memory block has not been subsequently deallocated, where
/// blocks are deallocated either by being passed to a deallocation
/// method such as `dealloc` or by being
/// passed to a reallocation method that returns a non-null pointer.
///
///
/// # Example
///
/// ```standalone_crate
/// use std::alloc::{GlobalAlloc, Layout};
/// use std::cell::UnsafeCell;
/// use std::ptr::null_mut;
/// use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
///
/// const ARENA_SIZE: usize = 128 * 1024;
/// const MAX_SUPPORTED_ALIGN: usize = 4096;
/// #[repr(C, align(4096))] // 4096 == MAX_SUPPORTED_ALIGN
/// struct SimpleAllocator {
/// arena: UnsafeCell<[u8; ARENA_SIZE]>,
/// remaining: AtomicUsize, // we allocate from the top, counting down
/// }
///
/// #[global_allocator]
/// static ALLOCATOR: SimpleAllocator = SimpleAllocator {
/// arena: UnsafeCell::new([0x55; ARENA_SIZE]),
/// remaining: AtomicUsize::new(ARENA_SIZE),
/// };
///
/// unsafe impl Sync for SimpleAllocator {}
///
/// unsafe impl GlobalAlloc for SimpleAllocator {
/// unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
/// let size = layout.size();
/// let align = layout.align();
///
/// // `Layout` contract forbids making a `Layout` with align=0, or align not power of 2.
/// // So we can safely use a mask to ensure alignment without worrying about UB.
/// let align_mask_to_round_down = !(align - 1);
///
/// if align > MAX_SUPPORTED_ALIGN {
/// return null_mut();
/// }
///
/// let mut allocated = 0;
/// if self
/// .remaining
/// .try_update(Relaxed, Relaxed, |mut remaining| {
/// if size > remaining {
/// return None;
/// }
/// remaining -= size;
/// remaining &= align_mask_to_round_down;
/// allocated = remaining;
/// Some(remaining)
/// })
/// .is_err()
/// {
Layout::array 恰好就是处理这类问题的标准工具repr(C) 字段偏移的例子。Layout::from_size_align(0, 1) 起步extendpad_to_align()+-----------+ consumes +-------------+
| Layout | --------------------> | Allocator |
|-----------| |-------------|
| size | | allocate |
| align | | grow/shrink |
+-----------+ +-------------+
| ^
| builds |
v |
+---------------+ uses offsets +-----------+
| repr(C) record | --------------------> | Raw memory |
+---------------+ +-----------+
Caller -> Layout: from_size_align(0, 1)
loop field in fields
Caller -> Layout: extend(field_layout)
Layout --> Caller: (new_layout, offset)
end
Caller -> Layout: pad_to_align()
Layout --> Caller: final repr(C) layout
Type/Capacity
↓
Layout::new / Layout::array / extend
↓
合法性检查(size, align, isize bound)
↓
Allocator::allocate / grow / shrink
↓
Global allocator / custom allocator
↓
Raw pointer / NonNull<[u8]>
for_value / for_value_raw 能通过胖指针长度恢复extend 可以精确模拟 repr(C)repr(Rust) 字段顺序和布局细节未承诺稳定align_to(32) 可能仍保持原 sizepad_to_alignextend_packed / repeat_packed 省掉了 paddingusize 能表示的范围比 Rust 指针偏移模型要求更大// 易错写法
let bytes = elem_size * n; // 只要一溢出就危险
// 更稳妥
let layout = Layout::array::<T>(n)?;dangling_ptr() 可能恰好落在一个“看起来有效”的地址Layout::new<T>()Layout::array<T>(n)extend + pad_to_align| 概念 | Rust Layout | 你真正得到的价值 |
|---|---|---|
| C 的 sizeof/alignof | 更强,带合法性检查 | 把错用拦在构造阶段 |
| 手写偏移计算 | extend / repeat API | 复用标准库算法 |
| 分配器参数包 | 统一语言 | 容器与 allocator 解耦 |
library/core/src/alloc/layout.rslibrary/core/src/alloc/mod.rsLayout::array访问链接:https://atcfu.com/ai-articles/rust-memory-layout/