Skip to main content

Heap

Struct Heap 

Source
pub struct Heap { /* private fields */ }
Expand description

One shard’s heap. Not Sync: exactly one thread owns it, which is what removes the atomics from the fast path.

Implementations§

Source§

impl Heap

Source

pub fn flush_claims(&mut self)

Retire every class’s claim — the write-back before anything that reads span occupancy as truth (reclaim’s page sweep, drop).

Source§

impl Heap

Source

pub fn drain_foreign(&mut self)

Move every slot other shards freed back onto its own span’s list.

Source§

impl Heap

Source

pub const fn new(id: usize) -> Self

A heap owning nothing. id identifies the shard in stats and in segment headers.

Source

pub const fn with_class_cap(id: usize, class_cap: u32) -> Self

A heap with a tighter per-class ceiling than PER_CLASS_CAP.

The default is a runaway guard set beyond any real workload, which leaves the refusal path unreachable in a test. This makes it reachable without pretending the default is smaller than it is.

Source

pub fn ensure_identity(&mut self)

Adopt this heap’s address as its identity, once.

Segments record their owner so a free arriving on the wrong thread can be routed home. The address of the heap itself is a ready-made unique identifier — no counter, no registry, and it cannot collide while the heap is alive. 0 means “not yet set”, which is why Heap::new can stay const.

Source

pub fn alloc(&mut self, size: usize, align: usize) -> Option<NonNull<u8>>

Allocate size bytes aligned to align, or None if the OS or a class cap says no.

Alignment up to class::MAX_NATIVE_ALIGN is served by choosing a suitable class. Stricter requests fall to the direct-mapping path, which returns page-aligned memory; anything beyond a page belongs to the GlobalAlloc shim’s over-aligned path.

Source

pub unsafe fn try_resize_in_place( &mut self, ptr: NonNull<u8>, old_size: usize, new_size: usize, align: usize, ) -> bool

Grow or shrink in place when the block’s size class does not change, reporting whether it worked.

This is the capability a general-purpose allocator gets from its chunk headers: glibc can often extend a block where it lies instead of moving it. Without it, GlobalAlloc’s default realloc allocates, copies and frees on every growth — and a profile of pub/sub showed exactly that, with libc realloc visible and cheap on the system side and nothing corresponding on ours.

Refuses when the block belongs to another thread. Adjusting the owner’s counters from here is precisely what this design does not do, and the caller falls back to allocate-copy-free, which routes the release home correctly.

§Safety

ptr must be a live allocation from this allocator made with old_size and align.

Source

pub unsafe fn dealloc(&mut self, ptr: NonNull<u8>, size: usize, align: usize)

Return an allocation. size must be the one it was made with — the sized-dealloc contract is what lets us store no headers.

§Safety

ptr must come from Self::alloc on this heap with this size, and must not be used afterwards.

Source§

impl Heap

Source

pub fn reclaim(&mut self)

Return free pages to the OS — whole spans where nothing is live, and individual pages inside spans that still are. The second half is v2 (RFC §5.1): M3 measured the whole-span rule returning 3 % because a span only empties when all its slots die together, while glibc works at page granularity. Now so do we.

Drains foreign frees first: slots parked by other shards pin their pages exactly as live slots do, so sweeping before draining under-returns for no reason.

The retained count is per sweep rather than cumulative. A running counter looked equivalent and was not: it only ever grew, so the second sweep found it already past the threshold and returned everything, which made the hysteresis vanish after one call.

Source§

impl Heap

Source

pub fn snapshot(&self) -> Stats

Where every mapped byte is (bench/V5-ACCOUNTING-CONTRACT.md §1).

Walks the segments rather than maintaining seven counters on the hot path: only live and rounding depend on the requested size and must be tracked as allocations happen. Stats are read on INFO, not per operation.

Trait Implementations§

Source§

impl Drop for Heap

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

§

impl !Send for Heap

§

impl !Sync for Heap

§

impl Freeze for Heap

§

impl RefUnwindSafe for Heap

§

impl Unpin for Heap

§

impl UnsafeUnpin for Heap

§

impl UnwindSafe for Heap

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.