Region Inference

コンパイル時にヒープメモリの割り当てと解放をすべて推論する手法。GC なしで安全なメモリ管理を実現する。Tofte & Talpin (1997) が理論的基盤を確立し、MLKit (Standard ML コンパイラ) で実装された。

基本アイデア

ヒープをリージョン (arena) に分割し、リージョン単位で一括定数時間解放する。

graph LR
    subgraph "リージョンスタック"
        R1["Region r₁<br/>(グローバル)"]
        R2["Region r₂<br/>(関数スコープ)"]
        R3["Region r₃<br/>(ループスコープ)"]
    end
    R3 -->|"letregion 終了<br/>一括解放"| Free["フリーリストに返却<br/>(定数時間)"]

Tofte & Talpin (1997) の理論

原論文: “Region-Based Memory Management” (Information and Computation, Vol.132, 1997)。初発表は POPL 1994。

型システムの拡張

ラムダ計算を2つの構成子で拡張する:

構文意味
e at ρ式 e の結果をリージョン ρ に格納
letregion ρ in e endリージョンを作成して ρ に束縛、e 評価後に一括解放

型にはリージョン注釈が付く: int at ρ = 「リージョン ρ に格納された整数値」。

Region Polymorphism (リージョンの多相性)

関数がリージョンパラメータを取る。呼び出し側が結果の格納先リージョンを選択:

(* 概念的な region-annotated コード *)
letrec fac [ρ_result] n =
  if n = 0 then 1 at ρ_result
  else n * fac [ρ_result] (n - 1)

fac はリージョンパラメータ [ρ_result] を取る多相関数。リージョン注釈における多相的再帰 (polymorphic recursion) が可能。

効果 (Effect) システム

型付け判断は型に加えて効果を関連付ける:

効果意味
put(ρ)リージョン ρ への書き込み
get(ρ)リージョン ρ からの読み取り

関数型の矢印に効果が注釈される: τ₁ →^{φ} τ₂ (φ は効果集合)。効果変数の単一化時に効果は和集合で結合される。

型推論アルゴリズム (Tofte & Birkedal, 1998)

2フェーズの制約ベースアルゴリズム:

  1. S アルゴリズム: 各値生成式にリージョン変数を生成し、letregion を挿入
  2. R アルゴリズム: 再帰関数のリージョン引数における多相的再帰を処理

ML の型推論と同様に単一化を用いるが、効果集合が主単一化子 (principal unifier) に対する問題を提起する。

正しさの保証

型安全性の証明により、解放済みリージョン内のオブジェクトへのアクセスが型システムによって静的に不可能となる。

MLKit コンパイラの実装

MLKit とは

Standard ML コンパイラ。1989年からエディンバラ大学で Elsman & Tofte が開発。最新: v4.7.21 (2026年1月)。ソース SML にはリージョン注釈が一切不要 (完全自動推論)。

コンパイルパイプラインでの位置

graph LR
    SML["SML ソース"] --> Parse["パース"] --> Lambda["Lambda IR"] --> Opt["Lambda 最適化"]
    Opt --> RI["Region Inference"]
    RI --> MU["Multiplicity<br/>Inference"]
    MU --> PS["Physical Size<br/>Inference"]
    PS --> SM["Storage Mode<br/>Analysis"]
    SM --> CG["コード生成"]

Region Inference 後の追加解析

解析内容
Multiplicity Inference各リージョンへの書き込み回数を推論 (0, 1, ∞)
Physical Size Inferenceリージョンが有限 (スタック上) か無限 (ページリンクリスト) かを判定
Storage Mode Analysis無限リージョンの格納モードを決定: attop (追加) / atbot (リセット後格納) / sat (実行時判定)

ランタイム表現

Bump Allocator との関係

リージョンは本質的に bump allocator + スコープ (ライフタイム管理):

概念リージョンBump Allocator
割り当てbump-pointer を進める同じ
解放リージョン一括解放全体リセット
letregionスコープ付きの save/restorebump pointer の save/restore
個別 freeなしなし

Hanson (1990) が示したように、bump-pointer 方式は最速の malloc より高速に動作する。

制限・既知の問題

Space Leaks (空間リーク)

純粋なスタックベースリージョン体系では不可避の問題。

パターン説明
LIFO 制約による長寿命化大きなデータ構造と小さな結果が同一リージョンに共存。小さな値だけ必要でもリージョン全体が生存
グローバルリージョンへの退避ライフタイムを推論できないデータがプログラム全体の寿命を持つリージョンに配置される
リスト全要素の同一リージョン制約同じリストの全要素は同じリージョン。一部が不要でもリスト全体のリージョンが生存

Region Explosion

高階関数や複雑な再帰で推論されるリージョン数が爆発的に増加。

対策

対策内容
Storage Mode Analysisatbot でリージョンをリセットして再利用
Region ResettingresetRegion で既存データを破棄
Region ProfilingMLKit 付属のプロファイラで空間リーク特定
ハイブリッド GCリージョン推論 + 参照追跡 GC の併用 (Hallenberg, Elsman & Tofte, PLDI 2002)

関連する研究・言語

Cyclone (2002, PLDI)

Grossman, Morrisett らによる安全な C 方言。C にリージョンベースメモリ管理を追加。明示的なリージョン注釈が必要 (レガシー C からの移植で約 8% のコード変更)。動的リージョン、ユニークポインタ、参照カウントの統合。

Rust のライフタイム

Rust のバロウチェッカはリージョン推論の影響を受けているが、本質的に異なる:

観点Tofte-TalpinRust
追跡対象値の配置先 (どのリージョンに格納されるか)参照のライフタイム (借用が有効な範囲)
スコープレキシカル (letregion)非レキシカル (NLL, 制御フローグラフベース)
安全性保証効果システム (put/get)所有権 + 借用規則
注釈完全自動推論一部プログラマが明示注釈

Rust 内部では実際にリージョン変数 (RegionVid) を使い、outlives 制約 ('a: 'b) を伝播・解決する。

Linear Regions Are All You Need (Fluet, Morrisett, Ahmed, ESOP 2006)

線形型とリージョンの組み合わせだけで安全なメモリ解放が実現できることを証明。Tofte-Talpin の効果システムの代替として、線形能力 (linear capability) によるリージョン管理を提案。

Spegion (Hughes, Vollmer, Batty, ECOOP 2025)

暗黙的・非レキシカルなリージョンとサイズ付き割り当て。ソース言語からファーストクラスのリージョン構文を除去し、C 系言語との自然な互換性を実現。効果ベースの型システムで安全性を保証。

WASM への適用可能性

リージョンベース管理は WASM に本質的に適する:

押さえどころ(カード化候補)

関連

Graph