---
title: Allocator 与内存布局
url: https://doc.liz6.com/rust/04-smart-pointers-and-memory/03-allocator-and-memory-layout
locale: zh
area: rust
tags:
- rust
- 智能指针与内存
date: 2026-06-30
modified: 2026-06-30
description: 'Rust 默认用系统的 malloc/free,但可以通过 GlobalAlloc trait 替换全局分配器或给特定容器指定自定义分配器。Layout 描述内存的大小和对齐,Pin 保证值不可移动(对自引用类型和异步 Future 至关重要),#[repr(align)] 和 #[repr(C)] 精确控制内存布局。'
---

# Allocator 与内存布局

> Rust 默认用系统的 malloc/free,但可以通过 GlobalAlloc trait 替换全局分配器或给特定容器指定自定义分配器。Layout 描述内存的大小和对齐,Pin 保证值不可移动(对自引用类型和异步 Future 至关重要),`#[repr(align)]` 和 `#[repr(C)]` 精确控制内存布局。

## 默认分配器

Rust 默认用系统的 `malloc/free`（glibc 的 ptmalloc2 on Linux），但可以替换。实现 `GlobalAlloc` trait 并标记 `#[global_allocator]`：

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

struct MyAllocator;
unsafe impl GlobalAlloc for MyAllocator {
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        // 实现分配逻辑: 从预分配的 buffer 切一块, 或调 mmap, ...
    }
    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
        // 实现释放逻辑
    }
}

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

常用替代分配器：`mimalloc`（Microsoft，低碎片）、`jemalloc`（FreeBSD，多线程优化）、`snmalloc`（Microsoft Research，message-passing based）。

## Layout: 分配请求的描述

分配器不直接接收"给我 N bytes"——而是接收 `Layout` 结构，包含大小和对齐：

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

分配器必须返回满足对齐要求的内存。如果分配失败，返回 `null`（不是 panic）。

## allocator API: 手动分配

```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) };
```

这几乎是 C 的 `malloc/free`，加了类型安全的 Layout 参数。绝大多数代码不需要直接调 alloc——`Box`, `Vec`, `String` 等已处理。

## Pin: 保证不被移动

Rust 的 move semantics 意味着任何值都可以被 memcpy 到新地址。但对于自引用结构（struct 的字段引用同一个 struct 的另一个字段），move 后引用变成悬垂。`Pin` 保证 pinned 的值不会再被 move：

```rust
use std::pin::Pin;
// 典型的自引用结构 (简化):
struct SelfRef { value: String, ptr: *const String }
// 构造时 ptr 指向 value, 但如果 SelfRef 被 move → ptr 悬垂
// Pin<Box<SelfRef>> 保证 SelfRef 不会被 move — 安全
```

`async fn` 生成的 Future 是典型的自引用结构——它引用了 await 点之前的局部变量。`Pin<&mut Future>` 保证在 poll 期间 Future 不会被 move。这是 async/await 编译器的内部实现基础。

## 参考

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

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