liveBook · Manning

Memory allocator

As explained in Code Like a Pro in Rust

The Allocator trait is a Rust trait that defines operations and behavior for types representing memory allocators.

A memory allocator manages heap storage for values whose size or lifetime calls for dynamic allocation. In Rust, Vec and Box request heap storage without requiring you to manage the allocator directly. Stack allocation is generally faster; on memory-constrained systems, avoiding a heap may be preferable. section 5.1 section 5.10

Implement the Allocator trait when a data structure needs custom allocation behavior. Its required methods are allocate, which receives a Layout and returns a memory region or AllocError, and unsafe deallocate, which releases a region using its layout. The trait supplies defaults for zeroed allocation, growth, and shrinking; default growth and shrinking allocate, copy, then release the old region. Allocation code commonly requires unsafe operations. section 5.8.1

Listing 5.11 Code for a pass-through allocator
#![feature(allocator_api)]

use std::alloc::{AllocError, Allocator, Global, Layout};
use std::ptr::NonNull;

pub struct PassThruAllocator;

unsafe impl Allocator for PassThruAllocator {
 fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
     Global.allocate(layout)
 }
 unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
     Global.deallocate(ptr, layout)
 }
}

A minimal pass-through implementation delegates both required methods to Global; it provides a starting point before changing allocation behavior. section 5.8.1

Use an allocator with Vec

Construct a vector with Vec::with_capacity_in(10, BasicAllocator), then push values into it. The demonstrated BasicAllocator calls C malloc and free. Treat that listing as a basic example, not a portable template: Layout specifies both size and alignment, and both must be handled. These allocator API examples require a nightly toolchain and #![feature(allocator_api)]. section 5.8.1

Custom allocation can serve a single data structure rather than the entire program. A protected-memory allocator, for example, obtains page-aligned storage through platform-specific functions, places protected regions before and after the active region, and returns a slice of the active region. This supports memory protection for sensitive data such as secret keys. Its deallocation path must account for the surrounding regions. section 5.8.2

Choose the scope first: use Allocator for per-structure behavior; GlobalAlloc is another customization API, including for embedded systems that need a heap. If dynamic allocation is unnecessary, fixed-size data structures from heapless avoid it altogether. section 5.8.2 section 2.12.1

How Code Like a Pro in Rust covers it

How deep it goes
Works through required trait methods, default operations, a pass-through implementation, a C allocator, and partial page-aligned allocation and deallocation.
Examples
Uses a Global-delegating allocator, a malloc/free-backed Vec, and a page-aligned allocator with protected regions around sensitive storage.
What it assumes
Assumes Rust trait and unsafe-code familiarity; introduces the Allocator methods and their default behavior without re-teaching basic Rust syntax.
What you can do after
Build it from scratch by implementing allocate and deallocate, then use the allocator with Vec while accounting for layout and platform requirements.
How it connects
Connects heap allocation to Vec, Box, Layout, GlobalAlloc, unsafe code, and operating-system memory protection.

Also explained in

Compare how 2 books explain memory allocator →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Code Like a Pro in Rust. The section links point to the parts of the book it draws on.