このページの目次

アロケータとメモリレイアウト

Rust はデフォルトでシステムの malloc/free を使用しますが、GlobalAlloc トレイトを実装してグローバルアロケータを置き換えたり、特定コンテナにカスタムアロケータを指定したりできます。Layout はメモリサイズとアライメントを記述し、Pin は値の移動を防止します(自己参照型や非同期 Future に不可欠)。#[repr(align)] および #[repr(C)] によりメモリレイアウトを精密に制御できます。

デフォルトアロケータ

Rust はデフォルトでシステムの malloc/free(Linux では glibc の ptmalloc2)を使用しますが、置き換えることができます。GlobalAlloc トレイトを実装し、#[global_allocator] でマークします:

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

struct MyAllocator;
unsafe impl GlobalAlloc for MyAllocator {
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        // 割り当てロジックの実装: 事前に確保したバッファから切り出す、または mmap を呼び出す、など
    }
    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
        // 解放ロジックの実装
    }
}

#[global_allocator]
static GLOBAL: MyAllocator = MyAllocator;

一般的な代替アロケータ:mimalloc(Microsoft、フラグメンテーションが低い)、jemalloc(FreeBSD、マルチスレッド最適化済み)、snmalloc(Microsoft Research、メッセージパッシングベース)。

Layout: 割り当てリクエストの記述

アロケータは直接「N バイトください」というリクエストを受け取るのではなく、サイズとアライメントを含む Layout 構造体を受け取ります:

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

アロケータは、アライメント要件を満たすメモリを返さなければなりません。割り当てに失敗した場合は、null を返します(パニックしません)。

allocator API: 手動割り当て

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

これは、型安全な Layout パラメータが追加された C の malloc/free にほぼ相当します。ほとんどのコードでは alloc を直接呼び出す必要はありません。BoxVecString などが既に処理してくれます。

Pin: 移動の防止

Rust のムーブセマンティクスでは、任意の値が新しいアドレスに memcpy される可能性があります。しかし、自己参照構造体(struct のフィールドが同じ struct の別のフィールドを参照している場合)では、ムーブ後に参照がダングリングになります。Pin は、ピン留めされた値がそれ以上ムーブされないことを保証します:

use std::pin::Pin;
// 典型的な自己参照構造体(簡略化版):
struct SelfRef { value: String, ptr: *const String }
// 構築時に ptr は value を指しますが、SelfRef がムーブされると → ptr がダングリングする
// Pin<Box<SelfRef>> は SelfRef がムーブされないことを保証し、安全です

async fn から生成される Future は典型的な自己参照構造体です。これは、await ポイントより前のローカル変数を参照します。Pin<&mut Future> は、poll 中に Future がムーブされないことを保証します。これが async/await コンパイラの内部実装の基盤です。

参考

  • Rustonomicon: アロケータ、Pin
  • RFC 1398: カスタムアロケータ
  • RFC 2349: Pin

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