# 機能設計書 6-メモリプール

## 概要

本ドキュメントは、mrubyのメモリプール機能の設計を記述する。コンパイラ等で使用されるページベースのメモリプールであり、アライメント対応のブロック管理を行う。

### 本機能の処理概要

メモリプールは、コンパイラのようにまとまったメモリ割り当て・一括解放パターンに最適化されたアロケータである。ページ単位でメモリを管理し、個別の解放は行わず、プール全体を一括で解放する。

**業務上の目的・背景**：コンパイラのパース・コード生成フェーズでは多数の小さなメモリブロックが必要だが、個別に解放する必要はなく、フェーズ完了後に一括解放すればよい。メモリプールはこのパターンに最適化されており、個別のmalloc/freeのオーバーヘッドを回避する。

**機能の利用シーン**：mrubyコンパイラ（mrbgems/mruby-compiler）でのパース処理中のメモリ管理。

**主要な処理内容**：
1. `mempool_open()` - メモリプールの生成
2. `mempool_alloc()` - メモリプールからのブロック割り当て
3. `mempool_realloc()` - 最後に割り当てたブロックの再割り当て
4. `mempool_close()` - メモリプールの一括解放

**関連システム・外部連携**：メモリアロケータ（mrb_basic_alloc_func）。コンパイラ。

**権限による制御**：なし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面機能マッピングにデータなし |

## 機能種別

メモリ管理処理（プールアロケータ）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| pool | mempool* | Yes | メモリプールポインタ | NULLチェック |
| len | size_t | Yes | 要求割り当てサイズ | - |
| p | void* | No | 再割り当て元ポインタ（realloc時） | - |
| oldlen | size_t | No | 旧サイズ（realloc時） | - |

### 入力データソース

コンパイラからの割り当てリクエスト。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ポインタ | void* | 割り当てられたメモリブロック |
| プールポインタ | mempool* | 新規生成されたメモリプール（open時） |

### 出力先

呼び出し元への戻り値。

## 処理フロー

### 処理シーケンス

```
1. mempool_open()
   └─ mempool構造体割り当て、pages=NULL初期化
2. mempool_alloc(pool, len)
   ├─ アライメントパディング追加
   ├─ 既存ページにスペースあり → オフセット進めて返却
   └─ 新規ページ割り当て → ページリスト先頭に追加
3. mempool_realloc(pool, p, oldlen, newlen)
   ├─ 最後の割り当てかつ同一ページ内に収まる → インプレース拡張
   └─ それ以外 → mempool_alloc + memcpy
4. mempool_close(pool)
   └─ 全ページを順次free、pool構造体もfree
```

### フローチャート

```mermaid
flowchart TD
    A[mempool_alloc] --> B[アライメント計算]
    B --> C{既存ページに空きあり?}
    C -->|Yes| D[オフセット進めて返却]
    C -->|No| E[page_alloc: 新規ページ]
    E --> F[ページリスト先頭に追加]
    F --> D
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | アライメント | POOL_ALIGNMENT（64bit:8, 32bit:4）に合わせる | 全割り当て |
| BR-02 | ページサイズ | POOL_PAGE_SIZE=16000がデフォルト最小ページサイズ | ページ割り当て時 |
| BR-03 | インプレースrealloc | 最後の割り当てかつ同一ページ内に収まる場合のみ可能 | realloc時 |

### 計算ロジック

- アライメントパディング: `ALIGN_PADDING(x) = ((SIZE_MAX - x + 1) & (POOL_ALIGNMENT - 1))`

## データベース操作仕様

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| NULL返却 | メモリ不足 | malloc失敗 | メモリ増加 |
| NULL返却 | 不正引数 | pool=NULL | プールの正しい初期化 |

### リトライ仕様

リトライ機構なし。

## トランザクション仕様

該当なし

## パフォーマンス要件

- 個別のfreeが不要なため高速な割り当て
- ページ単位の一括解放で効率的なメモリ回収

## セキュリティ考慮事項

- 割り当てメモリのゼロ初期化は行わない（呼び出し側の責任）

## 備考

- mempool.cは226行（テストコード含む）
- `TEST_POOL`定義時にスタンドアロンテスト用のmain関数が有効になる
- mrubyのmalloc/freeマクロにより、プール内部ではmrb_basic_alloc_funcが使用される

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | mempool.c | `src/mempool.c` | mempool_page構造体（37-43行目）: next, offset, len, last, page[] |
| 1-2 | mempool.c | `src/mempool.c` | mempool構造体（52-54行目）: pagesポインタのみ |
| 1-3 | mempool.c | `src/mempool.c` | 設定定数（14-24行目）: POOL_ALIGNMENT, POOL_PAGE_SIZE |

**読解のコツ**: mempool_pageのpage[]はフレキシブル配列メンバ（C99）。構造体末尾の可変長データ領域。

#### Step 2: 主要操作を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | mempool.c | `src/mempool.c` | mempool_open()（81-90行目）: プール生成 |
| 2-2 | mempool.c | `src/mempool.c` | mempool_alloc()（141-164行目）: ページ走査→割り当て |
| 2-3 | mempool.c | `src/mempool.c` | mempool_realloc()（175-205行目）: インプレース拡張または新規割り当て+コピー |
| 2-4 | mempool.c | `src/mempool.c` | mempool_close()（97-110行目）: 全ページ一括解放 |
| 2-5 | mempool.c | `src/mempool.c` | page_alloc()（119-132行目）: 新規ページ割り当て |

**主要処理フロー**:
- **148-155行目**: 既存ページ走査でスペースのあるページを探索
- **156-163行目**: ページなし時の新規割り当てとリスト先頭追加
- **183-196行目**: lastポインタを使ったインプレースrealloc最適化

### プログラム呼び出し階層図

```
mempool_open()
    └─ malloc() ─── mempool構造体割り当て

mempool_alloc()
    ├─ [既存ページに空きあり] → オフセット更新
    └─ page_alloc() ─── 新規ページ
           └─ malloc() ─── ページメモリ割り当て

mempool_realloc()
    ├─ [インプレース可能] → オフセット更新
    └─ mempool_alloc() + memcpy

mempool_close()
    └─ free() × N ─── 全ページ + プール構造体
```

### データフロー図

```
[入力]                     [処理]                         [出力]

(なし) ──────────────────▶ mempool_open()               ──▶ mempool*
size ────────────────────▶ mempool_alloc()              ──▶ void* (ブロック)
(p, oldlen, newlen) ─────▶ mempool_realloc()            ──▶ void* (拡張ブロック)
mempool* ────────────────▶ mempool_close()              ──▶ (全メモリ解放)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| mempool.c | `src/mempool.c` | ソース | メモリプール実装 |
| mempool.h | `include/mruby/mempool.h` | ヘッダ | メモリプールAPI宣言 |
| allocf.c | `src/allocf.c` | ソース | 基盤メモリアロケータ（プール内部で使用） |
