# 機能設計書 84-ObjectSpace#memsize_of

## 概要

本ドキュメントは、mrubyのmruby-os-memsize gemが提供するObjectSpace.memsize_ofおよびObjectSpace.memsize_of_allメソッドの機能設計を記述する。オブジェクトが消費するヒープメモリ量を取得する機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：組み込みシステムではメモリリソースが限られるため、オブジェクトのメモリ消費量を把握することが重要である。本機能は、個別オブジェクトまたは全オブジェクトのメモリ使用量をsize_t単位で計測し、メモリプロファイリングやリーク検出に役立てる。

**機能の利用シーン**：メモリ使用量のモニタリング、メモリリーク検出、メモリ最適化の分析、特定クラスのインスタンスが消費するメモリ総量の把握に使用される。

**主要な処理内容**：
1. `ObjectSpace.memsize_of(obj)` - 個別オブジェクトのヒープメモリ消費量を返す
2. `ObjectSpace.memsize_of_all([klass])` - 全オブジェクト（またはklassの全インスタンス）のメモリ消費量合計を返す
3. オブジェクト型別のメモリサイズ計算（String、Array、Hash、Proc、Class等）

**関連システム・外部連携**：mruby-objectspace gem（依存先）、GCシステム

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | CLI | 参照画面 | mrubyスクリプト内でObjectSpace.memsize_ofを呼び出す |

## 機能種別

計算処理（メモリサイズ計測）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| obj (memsize_of) | Object | Yes | メモリサイズを計測する対象オブジェクト | - |
| klass (memsize_of_all) | Class | No | フィルタリング用クラス。省略時は全オブジェクト | - |

### 入力データソース

Ruby関数呼び出しの引数

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| メモリサイズ | Integer | ヒープメモリ消費量（バイト単位） |

### 出力先

Ruby関数の戻り値

## 処理フロー

### 処理シーケンス

```
1. ObjectSpace.memsize_of(obj)
   ├─ mrb_get_arg1(mrb) でオブジェクト取得
   ├─ os_memsize_of_object(mrb, obj) でサイズ計算
   │   ├─ mrb_type(obj) でオブジェクト型判定
   │   ├─ 型別のサイズ計算:
   │   │   ├─ MRB_TT_STRING: スロットサイズ + 非埋め込み時はバッファサイズ
   │   │   ├─ MRB_TT_CLASS/MODULE: スロットサイズ + メソッドテーブルサイズ + IV
   │   │   ├─ MRB_TT_OBJECT: スロットサイズ + IVテーブルサイズ
   │   │   ├─ MRB_TT_HASH: スロットサイズ + ハッシュ内部サイズ
   │   │   ├─ MRB_TT_ARRAY: スロットサイズ + 埋め込み超過時のポインタ配列
   │   │   ├─ MRB_TT_PROC: スロットサイズ + 環境サイズ + irep
   │   │   ├─ MRB_TT_FIBER: スロットサイズ + コンテキストサイズ
   │   │   └─ その他: 型に応じた計算
   └─ mrb_fixnum_value で返却

2. ObjectSpace.memsize_of_all([klass])
   ├─ mrb_get_args でオプションのクラスフィルタ取得
   ├─ mrb_objspace_each_objects でGCヒープ全走査
   │   ├─ 各オブジェクトについて:
   │   │   ├─ 内部オブジェクト（FREE, ENV等）はスキップ
   │   │   ├─ c==NULLのProcオブジェクトはスキップ
   │   │   └─ klassフィルタに一致するもののみ加算
   └─ 合計値をmrb_fixnum_valueで返却
```

### フローチャート

```mermaid
flowchart TD
    A[memsize_of呼び出し] --> B[オブジェクト型判定]
    B --> C{即値?}
    C -->|Yes| D[0を返却]
    C -->|No| E[型別サイズ計算]
    E --> F[スロットサイズ + 型固有サイズ]
    F --> G[Integerとして返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-84-1 | 即値ゼロ | Integer、Symbol、true、false等の即値は0を返す | 即値オブジェクト |
| BR-84-2 | スロットサイズ | ヒープ割り当てオブジェクトはページスロットサイズを含む | 非即値オブジェクト |
| BR-84-3 | 埋め込み判定 | 文字列・配列は埋め込みサイズ以下なら追加ヒープなし | String, Array |
| BR-84-4 | irep再帰計算 | Procのirepサイズは子irepも含めて再帰的に計算 | Proc, Method |

### 計算ロジック

型別メモリサイズ計算:
- String: `page_slot_size + RSTRING_CAPA + 1` (非埋め込み・非共有時)
- Array: `page_slot_size + sizeof(mrb_value*) * len` (len > MRB_ARY_EMBED_LEN_MAX時)
- Hash: `page_slot_size + mrb_hash_memsize(obj)`
- Proc: `page_slot_size + env_len * sizeof(mrb_value) + irep_size` (非C関数時)
- Fiber: `page_slot_size + sizeof(mrb_context) + stack_size + ci_size`

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | - | 特になし | - |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

- memsize_of: O(1)（irepの再帰計算を除く）
- memsize_of_all: O(N)（Nはヒープ上の全オブジェクト数）。大量オブジェクト時は時間がかかる可能性がある。

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

特になし

## 備考

- mruby-objectspaceに依存（mrb_objspace_each_objects、mrb_objspace_page_slot_size使用）
- テスト時にmruby-metaprog、mruby-method、mruby-fiberに依存
- 戻り値はプラットフォームのsize_tに依存するため、異なるプラットフォーム間での値比較は不可

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | memsize.c | `mrbgems/mruby-os-memsize/src/memsize.c` | `os_memsize_of_all_cb_data` 構造体（219-222行目）でコールバックデータを理解 |

**読解のコツ**: 本実装はmrubyの内部型（MRB_TT_*）を網羅的に扱う巨大なswitch文が核心。各MRB_TT_*定数の意味を把握することが重要。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | memsize.c | `mrbgems/mruby-os-memsize/src/memsize.c` | `mrb_mruby_os_memsize_gem_init`（260-266行目）でメソッド登録を確認 |

**主要処理フロー**:
1. **263行目**: ObjectSpaceモジュールを取得
2. **264行目**: `memsize_of` クラスメソッドを登録（引数1つ必須）
3. **265行目**: `memsize_of_all` クラスメソッドを登録（引数0-1個）

#### Step 3: irep再帰サイズ計算を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | memsize.c | `mrbgems/mruby-os-memsize/src/memsize.c` | `os_memsize_of_irep`（17-39行目）でirepの再帰的サイズ計算を確認 |

**主要処理フロー**:
- **19-22行目**: シンボルテーブル、プール、命令列、子irepポインタのサイズを加算
- **24-32行目**: プール値のサイズ（文字列プールとbigint）を加算
- **34-38行目**: 子irepを再帰的にサイズ計算

#### Step 4: 型別メモリサイズ計算を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | memsize.c | `mrbgems/mruby-os-memsize/src/memsize.c` | `os_memsize_of_object`（67-193行目）で型別計算を確認 |

**主要処理フロー**:
- **73-79行目**: MRB_TT_STRING - 埋め込み・共有判定、非埋め込み時はCAPAを加算
- **80-95行目**: MRB_TT_CLASS/MODULE/OBJECT - メソッドテーブル + IVテーブル + Method/UnboundMethod判定
- **96-99行目**: MRB_TT_HASH - ハッシュ内部サイズ
- **101-109行目**: MRB_TT_ARRAY/STRUCT - 埋め込み超過時のポインタ配列
- **111-118行目**: MRB_TT_PROC - 環境変数 + irep
- **119-135行目**: MRB_TT_FIBER - コンテキスト + スタック + callinfo

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

```
mrb_mruby_os_memsize_gem_init
    │
    ├─ ObjectSpace.memsize_of ──▶ os_memsize_of
    │                               └─ os_memsize_of_object
    │                                    ├─ mrb_objspace_page_slot_size
    │                                    ├─ mrb_class_mt_memsize
    │                                    ├─ mrb_obj_iv_tbl_memsize
    │                                    ├─ mrb_hash_memsize
    │                                    ├─ os_memsize_of_irep (再帰)
    │                                    └─ os_memsize_of_method
    │
    └─ ObjectSpace.memsize_of_all ──▶ os_memsize_of_all
                                        └─ mrb_objspace_each_objects
                                             └─ os_memsize_of_all_cb
                                                  └─ os_memsize_of_object
```

### データフロー図

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

オブジェクト ───▶ os_memsize_of_object ───▶ size_t (バイト数)
                     │
                     ├─ mrb_type() で型判定
                     ├─ 型別サイズ計算
                     └─ irep再帰計算 (Proc/Method)

クラス(opt) ───▶ mrb_objspace_each_objects ───▶ 合計バイト数
                     └─ 全オブジェクト走査
                          └─ クラスフィルタ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| memsize.c | `mrbgems/mruby-os-memsize/src/memsize.c` | ソース | memsize_of/memsize_of_all実装 |
| mrbgem.rake | `mrbgems/mruby-os-memsize/mrbgem.rake` | 設定 | gem仕様定義、依存関係 |
| memsize.rb | `mrbgems/mruby-os-memsize/test/memsize.rb` | テスト | テストケース |
