# 機能設計書 45-ObjectSpaceクラス

## 概要

本ドキュメントは、mruby-objectspace gemが提供するObjectSpaceモジュールの機能設計を記述する。オブジェクト空間内のオブジェクトを型別にカウントする機能と、全オブジェクトを列挙するイテレーション機能を提供する。

### 本機能の処理概要

mruby-objectspace gemは、mrubyのGCヒープ内に存在する全オブジェクトに対するリフレクション機能を提供する。全てC言語(src/mruby_objectspace.c)で実装されている。ObjectSpaceモジュールのクラスメソッドとして2つのメソッドを定義する。

**業務上の目的・背景**：プログラムのメモリ使用状況の分析、デバッグ、リフレクションのために、オブジェクト空間へのアクセスが必要な場合がある。ObjectSpaceモジュールはオブジェクトの型別カウントや全オブジェクトの列挙を可能にし、メモリリークの検出やオブジェクト生成パターンの分析に活用できる。

**機能の利用シーン**：メモリ使用状況のモニタリング（count_objects）、特定クラスのインスタンスの列挙（each_object）、デバッグ時のオブジェクト調査、テスト時のオブジェクトリーク検出に使用される。

**主要な処理内容**：
1. ObjectSpace.count_objects - オブジェクトを型別にカウントしてハッシュで返す
2. ObjectSpace.each_object - 全オブジェクトまたは特定クラスのオブジェクトを列挙する

**関連システム・外部連携**：mrubyコアのGCシステム（mrb_objspace_each_objects）に直接依存する。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はライブラリ機能であり、画面との関連はない |

## 機能種別

リフレクション / デバッグ支援

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| result_hash (count_objects) | Hash | No | 結果を格納するハッシュ（再利用用） | Hashオブジェクト |
| module (each_object) | Module/Class | No | フィルタリング対象のモジュール/クラス | モジュールまたはクラス |
| block (each_object) | Block | Yes | 各オブジェクトに対して実行するブロック | ブロック必須 |

### 入力データソース

mrubyのGCヒープ（オブジェクト空間）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| count_objects戻り値 | Hash | 型シンボルをキー、カウントを値とするハッシュ |
| each_object戻り値 | Integer | イテレーションしたオブジェクトの総数 |

### 出力先

メソッドの戻り値として呼び出し元に返却

## 処理フロー

### 処理シーケンス

```
1. ObjectSpace.count_objects(result_hash=nil)
   ├─ 引数なし: 新しいHashを作成
   ├─ 引数あり: 既存Hashをクリア
   ├─ mrb_objspace_each_objectsでオブジェクト走査
   │   └─ os_count_object_typeコールバックで型別カウント
   ├─ :TOTALと:FREEをHashに追加
   └─ 各型(T_OBJECT, T_CLASS等)のカウントをHashに追加

2. ObjectSpace.each_object(module=nil, &block)
   ├─ ブロック必須（なしの場合ArgumentError）
   ├─ mrb_objspace_each_objectsでオブジェクト走査
   │   └─ os_each_object_cbコールバック
   │       ├─ 死んだオブジェクトをフィルタ
   │       ├─ 内部オブジェクト(FREE, ENV, BREAK, ICLASS)をフィルタ
   │       ├─ classポインタがないオブジェクトをフィルタ
   │       ├─ module指定時: is_kind_ofでフィルタ
   │       └─ ブロックにオブジェクトをyield
   └─ カウントを返す
```

### フローチャート

```mermaid
flowchart TD
    A[ObjectSpace.each_object] --> B{ブロックあり?}
    B -->|No| C[ArgumentError]
    B -->|Yes| D[mrb_objspace_each_objects]
    D --> E[os_each_object_cb]
    E --> F{オブジェクトは生存?}
    F -->|No| G[スキップ]
    F -->|Yes| H{内部型?}
    H -->|Yes| G
    H -->|No| I{classあり?}
    I -->|No| G
    I -->|Yes| J{module指定?}
    J -->|Yes| K{kind_of match?}
    K -->|No| G
    K -->|Yes| L[yield obj]
    J -->|No| L
    L --> M[count++]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-45-01 | 内部オブジェクト除外 | FREE, ENV, BREAK, ICLASSはeach_objectの対象外 | each_object走査時 |
| BR-45-02 | 死んだオブジェクト除外 | GC管理で解放済みマークのオブジェクトは除外 | 両メソッド走査時 |
| BR-45-03 | probe effect回避 | count_objectsでresult_hashを渡すことでハッシュ生成を避けられる | count_objects呼び出し時 |
| BR-45-04 | 型カウント対象 | MRB_TT_FALSEからMRB_TT_MAXDEFINEまでの全型をカウント | count_objects走査時 |

### 計算ロジック

count_objectsのカウント: `obj_count.counts[obj->tt]++`で型別に加算。TOTALは全オブジェクト数、FREEは死んだオブジェクト数。

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ArgumentError | each_objectにブロックなしで呼んだ場合 | ブロックを渡す |

### リトライ仕様

リトライは不要

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

該当なし

## パフォーマンス要件

両メソッドともO(n)（n=GCヒープ内の全オブジェクト数）で動作する。大量のオブジェクトが存在する場合は高コストになる可能性がある。

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

each_objectは全オブジェクトへのアクセスを可能にするため、オブジェクトの内部状態が意図せず公開される可能性がある。プロダクション環境での使用には注意が必要。

## 備考

- count_objectsで報告される型名はシンボル(例: :T_OBJECT, :T_CLASS)
- each_objectはGC走査を行うため、走査中のオブジェクト生成に注意
- mruby-class-ext gemのClass#subclassesもmrb_objspace_each_objectsを使用している

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | mruby_objectspace.c | `mrbgems/mruby-objectspace/src/mruby_objectspace.c` | os_count_struct構造体（15-19行目） |
| 1-2 | mruby_objectspace.c | `mrbgems/mruby-objectspace/src/mruby_objectspace.c` | os_each_object_data構造体（116-120行目） |

**読解のコツ**: `os_count_struct`はtotal(全オブジェクト数), freed(解放済み数), counts[MRB_TT_MAXDEFINE+1](型別カウント配列)を持つ。`os_each_object_data`はtarget_module(フィルタ用クラス), count(列挙数), block(ブロック)を持つ。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | mruby_objectspace.c | `mrbgems/mruby-objectspace/src/mruby_objectspace.c` | gem初期化（177-183行目） |

**主要処理フロー**:
1. **177-183行目**: `mrb_mruby_objectspace_gem_init` - ObjectSpaceモジュール定義、count_objectsとeach_objectをクラスメソッドとして登録

#### Step 3: count_objectsを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | mruby_objectspace.c | `mrbgems/mruby-objectspace/src/mruby_objectspace.c` | count_objects実装 |

**主要処理フロー**:
- **21-36行目**: `os_count_object_type` - コールバック関数。死んだオブジェクトはfreed++、生存はcounts[tt]++
- **58-114行目**: `os_count_objects` - ハッシュ初期化、全オブジェクト走査、結果ハッシュ構築
- **78-111行目**: COUNT_TYPEマクロで型シンボルに変換

#### Step 4: each_objectを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | mruby_objectspace.c | `mrbgems/mruby-objectspace/src/mruby_objectspace.c` | each_object実装 |

**主要処理フロー**:
- **122-152行目**: `os_each_object_cb` - コールバック関数。内部オブジェクト除外、moduleフィルタ、yield
- **168-175行目**: `os_each_object` - 引数パース(ブロック必須 + オプションmodule)、全オブジェクト走査

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

```
mrb_mruby_objectspace_gem_init
    |
    +-- mrb_define_module("ObjectSpace")
    +-- mrb_define_class_method("count_objects")
    |       +-- os_count_objects
    |               +-- mrb_objspace_each_objects
    |                       +-- os_count_object_type (callback)
    |                               +-- mrb_object_dead_p
    +-- mrb_define_class_method("each_object")
            +-- os_each_object
                    +-- mrb_objspace_each_objects
                            +-- os_each_object_cb (callback)
                                    +-- mrb_object_dead_p
                                    +-- mrb_obj_is_kind_of
                                    +-- mrb_yield
```

### データフロー図

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

(result_hash)       --> os_count_objects()           --> {:TOTAL=>n, :FREE=>m, :T_OBJECT=>x, ...}
GCヒープ全オブジェクト  --> mrb_objspace_each_objects   --> コールバック呼び出し

(module, &block)    --> os_each_object()             --> count (Integer)
GCヒープ全オブジェクト  --> mrb_objspace_each_objects   --> block.call(obj)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| mruby_objectspace.c | `mrbgems/mruby-objectspace/src/mruby_objectspace.c` | ソース | 全メソッドのC実装 |
| mrbgem.rake | `mrbgems/mruby-objectspace/mrbgem.rake` | 設定 | gem定義ファイル |
| objectspace.rb | `mrbgems/mruby-objectspace/test/objectspace.rb` | テスト | メソッドのテスト |
