# 機能設計書 77-GC制御

## 概要

本ドキュメントは、Julia言語におけるGC（ガベージコレクション）制御機能の設計を記述する。`GC.gc`、`GC.enable`、`GC.safepoint` などの関数によるガベージコレクションの手動制御を提供する。

### 本機能の処理概要

GC制御機能は、Juliaの自動メモリ管理システムであるガベージコレクタに対して、手動での収集トリガー、有効/無効の切り替え、セーフポイントの挿入、ファイナライザの制御、GCログの管理などの制御インタフェースを提供する。`Base.GC`モジュールとして実装されている。

**業務上の目的・背景**：自動GCは通常のアプリケーション開発では透過的に動作するが、リアルタイム処理、低レイテンシ要件のアプリケーション、メモリ管理のデバッグ、ベンチマークなどの場面ではGCの挙動を明示的に制御する必要がある。また、安全でないメモリ操作（ccall、ポインタ操作）との組み合わせにおいて、GCの動作タイミングを把握・制御することは安全性の確保に不可欠である。

**機能の利用シーン**：ベンチマーク前のGC強制実行による条件統一、リアルタイム処理区間でのGC無効化、@preserveによるccall中のオブジェクト保護、マルチスレッドプログラムでのセーフポイント挿入、GCログによるメモリ管理のデバッグなどで使用される。

**主要な処理内容**：
1. `GC.gc(full=true)` - GCの手動実行（フル/インクリメンタル）
2. `GC.enable(on::Bool)` - GCの有効/無効切り替え
3. `GC.@preserve x1 x2 ... expr` - GCからのオブジェクト保護
4. `GC.safepoint()` - GCセーフポイントの挿入
5. `GC.enable_finalizers(on::Bool)` - ファイナライザの有効/無効
6. `GC.in_finalizer()` - ファイナライザ実行中の判定
7. `GC.enable_logging(on::Bool)` - GCログの有効/無効
8. `GC.logging_enabled()` - GCログ状態の確認
9. `finalizer(f, x)` - オブジェクトへのファイナライザ登録
10. `finalize(x)` - ファイナライザの即時実行

**関連システム・外部連携**：Juliaランタイムの世代別GC（stock GC）またはMMTk GCと連携。ccallでCランタイム関数（jl_gc_collect, jl_gc_enable等）を呼び出す。

**権限による制御**：特別な権限制御はない。ただし、GCの無効化はメモリリークのリスクがある。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | REPLから直接GC.gc()等を呼び出して使用 |

## 機能種別

メモリ管理・制御処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| full | Bool | No | フルGCかインクリメンタルか（デフォルト: true） | true/false |
| on | Bool | Yes（enable） | GC有効/無効 | true/false |
| f | Function | Yes（finalizer） | ファイナライザ関数 | 呼び出し可能 |
| x | Any(mutable) | Yes（finalizer, @preserve） | 対象オブジェクト | mutable structであること |

### 入力データソース

- Juliaプログラムからの直接呼び出し

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| previous_state | Bool | GC.enable()の前の状態 |
| in_finalizer | Bool | GC.in_finalizer()の結果 |
| logging_state | Bool | GC.logging_enabled()の結果 |
| gc_impl | String | GC.gc_active_impl()のGC実装名 |

### 出力先

戻り値としてJuliaプログラムに返却。GCログはstderrに出力。

## 処理フロー

### 処理シーケンス

```
1. GC.gc() - GC手動実行
   └─ ccall(:jl_gc_collect, Cvoid, (Cint,), full ? GC_FULL : GC_INCREMENTAL)
2. GC.enable(on) - GC有効/無効切り替え
   └─ ccall(:jl_gc_enable, Int32, (Int32,), on) で前の状態を返却
3. GC.@preserve - オブジェクト保護
   └─ Expr(:gc_preserve, ...) をコンパイラに指示
4. GC.safepoint() - セーフポイント挿入
   └─ ccall(:jl_gc_safepoint, Cvoid, ())
5. finalizer(f, x) - ファイナライザ登録
   └─ _check_mutable(o) でmutable確認後、Core.finalizer(f, o)
```

### フローチャート

```mermaid
flowchart TD
    A[GC制御要求] --> B{操作の種類}
    B -->|GC.gc| C["jl_gc_collect(GC_FULL/GC_INCREMENTAL)"]
    B -->|GC.enable| D["jl_gc_enable(on)"]
    B -->|GC.@preserve| E["gc_preserve Expr生成"]
    B -->|GC.safepoint| F["jl_gc_safepoint()"]
    B -->|finalizer| G{"ismutable(o)?"}
    G -->|Yes| H["Core.finalizer(f, o)"]
    G -->|No| I["ErrorException"]
    C --> J[GC実行完了]
    D --> K[前の状態を返却]
    E --> L[コンパイラがオブジェクト参照を保持]
    F --> M[GC実行ポイント通過]
    H --> N[ファイナライザ登録完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-77-01 | GCモード | GC_AUTO=0, GC_FULL=1, GC_INCREMENTAL=2 | GC.gc() |
| BR-77-02 | デフォルトフルGC | GC.gc()のデフォルトはフルコレクション | full引数なし |
| BR-77-03 | mutable制約 | finalizerはmutable structにのみ登録可能 | finalizer呼び出し |
| BR-77-04 | ファイナライザ制限 | ファイナライザ内でタスクスイッチは禁止（println等不可） | ファイナライザ実行中 |
| BR-77-05 | @preserveのスコープ | @preserveは式の評価中のみオブジェクトを保護 | ccall等のunsafe操作 |
| BR-77-06 | セーフポイント速度 | セーフポイントは約2クロックサイクル | GC.safepoint() |
| BR-77-07 | ファイナライザカウンタ | enable_finalizersはカウンタベース。0でのみ実行 | enable_finalizers |

### 計算ロジック

特になし（制御操作のため）

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

### 操作別データベース影響一覧

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ErrorException | 例外 | 非mutable型にfinalizerを登録 | mutable structを使用 |
| error | @preserve | @preserveの引数がSymbolでない | Symbolを指定 |

### リトライ仕様

リトライ不要

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

該当なし

## パフォーマンス要件

- GC.gc()はフルコレクションの場合、ヒープサイズに比例する時間がかかる
- GC.safepoint()は約2クロックサイクルと極めて軽量
- GC.enable(false)によるGC無効化はメモリ使用量の無制限増加のリスクがある
- @preserveは通常、実行時パフォーマンスへの影響はない

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

- GCの無効化はメモリ使用量の無制限増加を引き起こす可能性がある（DoSリスク）
- ファイナライザ内でのI/O操作はデッドロックのリスクがある
- @preserveの不適切な使用はuse-after-freeのリスクに繋がる

## 備考

- WeakRefはGCにより参照先が回収される弱参照を提供
- GC.gc_active_impl()で現在のGC実装を確認可能（stock GC / MMTk等）
- full_sweep_reasons()でフルGCの発生理由を統計として取得可能

---

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

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

### 推奨読解順序

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

GC制御に関わるデータ型を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | gcutils.jl | `base/gcutils.jl` | WeakRef（1-32行目）: 弱参照の定義と等値比較 |
| 1-2 | gcutils.jl | `base/gcutils.jl` | GCモジュール定義（110-295行目）: GC_AUTO/GC_FULL/GC_INCREMENTAL定数 |

**読解のコツ**: GCモジュールは`base/gcutils.jl`内にネストモジュールとして定義されている。`public`宣言で公開APIが明示されている（112行目）。

#### Step 2: GC制御APIを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | gcutils.jl | `base/gcutils.jl` | GC.gc（133-134行目）: jl_gc_collectのccall。full→GC_FULL、false→GC_INCREMENTAL |
| 2-2 | gcutils.jl | `base/gcutils.jl` | GC.enable（146行目）: jl_gc_enableのccall。前の状態を返す |
| 2-3 | gcutils.jl | `base/gcutils.jl` | GC.safepoint（264行目）: jl_gc_safepointのccall |
| 2-4 | gcutils.jl | `base/gcutils.jl` | GC.@preserve（234-240行目）: gc_preserve Exprの生成 |

**主要処理フロー**:
1. **133-134行目**: `gc(full)` - full ? GC_FULL : GC_INCREMENTAL をjl_gc_collectに渡す
2. **146行目**: `enable(on)` - jl_gc_enable返り値 != 0 で前の状態
3. **234-240行目**: `@preserve` - 引数がSymbolであることを検証し、Expr(:gc_preserve, ...)を生成

#### Step 3: ファイナライザを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | gcutils.jl | `base/gcutils.jl` | finalizer（84-88行目）: _check_mutableで検証後、Core.finalizerを呼び出す |
| 3-2 | gcutils.jl | `base/gcutils.jl` | finalizer(Ptr)（90-95行目）: Cポインタのファイナライザ登録。jl_gc_add_ptr_finalizerを使用 |
| 3-3 | gcutils.jl | `base/gcutils.jl` | finalize（102-103行目）: jl_finalize_thで即時実行 |
| 3-4 | gcutils.jl | `base/gcutils.jl` | enable_finalizers / disable_finalizers（156-167行目）: カウンタベースの制御 |

**主要処理フロー**:
- **39-43行目**: `_check_mutable(o)` - ismutable(o)チェック、失敗時はErrorException
- **84-88行目**: `finalizer(f, o)` - _check_mutable → Core.finalizer → o返却
- **158-163行目**: `enable_finalizers()` - jl_gc_enable_finalizers_internal + pending finalizers実行

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

```
GC.gc(full=true)
    └─ ccall(:jl_gc_collect, Cvoid, (Cint,), GC_FULL)

GC.enable(on)
    └─ ccall(:jl_gc_enable, Int32, (Int32,), on) != 0

GC.@preserve x1 x2 expr
    └─ Expr(:gc_preserve, expr, x1, x2)
           └─ [コンパイラが参照を保持]

finalizer(f, o)
    │
    ├─ _check_mutable(o)
    │      └─ ismutable(o) || error(...)
    └─ Core.finalizer(f, o)

GC.safepoint()
    └─ ccall(:jl_gc_safepoint, Cvoid, ())
```

### データフロー図

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

full::Bool ──────▶ GC.gc()        ──────────▶ nothing (副作用: メモリ回収)
                    jl_gc_collect

on::Bool ────────▶ GC.enable()    ──────────▶ Bool (前の状態)
                    jl_gc_enable

f, o ────────────▶ finalizer()    ──────────▶ o (ファイナライザ登録済み)
                    Core.finalizer
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| gcutils.jl | `base/gcutils.jl` | ソース | GCモジュール、finalizer、WeakRefの定義 |
| gc-stock.c | `src/gc-stock.c` | ソース（C） | 世代別GCの実装 |
| gc-mmtk.c | `src/gc-mmtk.c` | ソース（C） | MMTk GCインタフェース |
| gc-interface.h | `src/gc-interface.h` | ヘッダ（C） | GCインタフェース定義 |
| gc-common.c | `src/gc-common.c` | ソース（C） | GC共通処理 |
| safepoint.c | `src/safepoint.c` | ソース（C） | セーフポイント実装 |
