---
title: Allocator and Memory Layout
url: https://doc.liz6.com/en/rust/04-smart-pointers-and-memory/03-allocator-and-memory-layout
locale: en
area: rust
tags:
- rust
- smart-pointers-and-memory
date: 2026-06-30
modified: 2026-07-16
description: 'Rust uses the system malloc/free by default, but you can replace the global allocator via the GlobalAlloc trait or specify a custom allocator for specific containers. Layout describes memory size and alignment, Pin ensures values are not moved (crucial for self-referential types and async Futures), and #[repr(align)] and #[repr(C)] provide precise control over memory layout.'
---

# Allocator and Memory Layout

> Rust uses the system `malloc/free` by default, but you can replace the global allocator via the `GlobalAlloc` trait or specify a custom allocator for specific containers. `Layout` describes memory size and alignment, `Pin` ensures values are not moved (crucial for self-referential types and async Futures), and `#[repr(align)]` and `#[repr(C)]` provide precise control over memory layout.

## Default Allocator

Rust uses the system `malloc/free` by default (ptmalloc2 from glibc on Linux), but this can be replaced. Implement the `GlobalAlloc` trait and mark it with `#[global_allocator]`:

```rust
use std::alloc::{GlobalAlloc, Layout, System};

struct MyAllocator;
unsafe impl GlobalAlloc for MyAllocator {
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        // Implement allocation logic: slice from a pre-allocated buffer, call mmap, etc.
    }
    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
        // Implement deallocation logic
    }
}

#[global_allocator]
static GLOBAL: MyAllocator = MyAllocator;
```

Common alternative allocators include: `mimalloc` (Microsoft, low fragmentation), `jemalloc` (FreeBSD, multi-threaded optimization), and `snmalloc` (Microsoft Research, message-passing based).

## Layout: Describing Allocation Requests

Allocators do not directly receive "give me N bytes"—instead, they receive a `Layout` struct containing size and alignment:

```rust
use std::alloc::Layout;
let layout = Layout::new::<u64>();   // size=8, align=8
let layout2 = Layout::from_size_align(1024, 64).unwrap();
```

The allocator must return memory that satisfies the alignment requirements. If allocation fails, it returns `null` (not a panic).

## Allocator API: Manual Allocation

```rust
use std::alloc::{alloc, dealloc, Layout};
let layout = Layout::new::<u64>();
let ptr = unsafe { alloc(layout) as *mut u64 };
unsafe { *ptr = 42 };
unsafe { dealloc(ptr as *mut u8, layout) };
```

This is almost identical to C's `malloc/free`, but with a type-safe `Layout` parameter. Most code does not need to call `alloc` directly—types like `Box`, `Vec`, and `String` handle this for you.

## Pin: Ensuring Immutability of Location

Rust's move semantics mean that any value can be `memcpy`'d to a new address. However, for self-referential structures (where a struct's field references another field within the same struct), moving the struct leaves references dangling. `Pin` ensures that pinned values will not be moved:

```rust
use std::pin::Pin;
// Typical self-referential structure (simplified):
struct SelfRef { value: String, ptr: *const String }
// When constructed, ptr points to value, but if SelfRef is moved → ptr becomes dangling
// Pin<Box<SelfRef>> guarantees that SelfRef will not be moved — safe
```

Futures generated by `async fn` are typical self-referential structures—they reference local variables from before the await point. `Pin<&mut Future>` guarantees that the Future will not be moved during polling. This is the foundational implementation detail for the async/await compiler.

## References

- **Rustonomicon**: Allocator, Pin
- **RFC 1398**: Custom allocators
- **RFC 2349**: Pin

*Keywords: GlobalAlloc, Layout, custom allocator, Pin, self-referential, #[repr(align)], alloc API*
