Files
hakorune/docs/説明書/reference/box-design/memory-management.md
Moe Charm e0f0a658e6 docs: Phase 9.75 Box設計根本革命 - SocketBox Arc<Mutex>責務一元化
 Phase 9.75実装計画追加:
- copilot_issues.txtにPhase 9.75追加(Phase 9.7と9.8の間)
- Arc<Mutex>二重化問題の根本解決計画
- 段階的実装戦略(Phase A-D)定義

📚 Box設計ドキュメント完全体系化:
- docs/説明書/reference/box-design/ 新設
- everything-is-box.md: 核心哲学の完全解説
- memory-management.md: Arc<Mutex>設計・fini/weak参照
- delegation-system.md: 完全明示デリゲーション仕様
- box-types-catalog.md: 全Box型の完全カタログ
- ffi-abi-specification.md: FFI/ABI仕様(移動済み)

🔧 実装ノート完備:
- current-issues.md: 現在進行中の設計課題
- socket-box-problem.md: Arc<Mutex>二重化問題詳細分析
- phase-9-75-redesign.md: 実装計画詳細

👥 Copilot実装ガイド作成:
- phase9_75_socketbox_arc_mutex_redesign.md
- SocketBox優先対応の具体的実装手順
- 完全テストスイート設計
- 段階的実装戦略(Step 1-5)

📋 CURRENT_TASK.md更新:
- Box設計ドキュメント完成記録
- Phase 9.75準備完了状況

🎯 効果:
- Everything is Box哲学の体系的文書化
- SocketBox問題解決の明確な道筋
- Copilot協調実装の準備完了
- 新規開発者オンボーディング改善

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-15 07:47:09 +09:00

6.9 KiB
Raw Blame History

🧠 Nyash メモリ管理設計

📋 概要

Nyashは「Everything is Box」哲学のもと、すべての値をBoxとして統一的に管理します。 メモリ安全性を保証しながら、シンプルで直感的なメモリ管理を実現しています。

🏗️ 基本アーキテクチャ

Arc一元管理

// インタープリターレベルでの統一管理
type NyashObject = Arc<Mutex<dyn NyashBox>>;

すべてのBoxは、インタープリターレベルでArc<Mutex>によって管理されます。 これにより:

  • スレッドセーフティ: 自動的に保証
  • 参照カウント: 自動的なメモリ解放
  • 統一的アクセス: すべて同じ方法で操作

アンチパターンPhase 9.75で修正中)

// 現在の問題: Box内部での二重ロック
pub struct BadBox {
    data: Arc<Mutex<String>>,  // ❌ Box内部でロック管理
}

// 正しい設計
pub struct GoodBox {
    data: String,  // ✅ シンプルなフィールド
}

🔄 fini()システム

概要

Nyashは決定論的なリソース解放のためにfini()システムを提供します。

box FileHandler {
    init { file }
    
    fini() {
        // オブジェクト削除時に自動呼び出し
        if me.file != null {
            me.file.close()
            console.log("File closed automatically")
        }
    }
}

fini()の特徴

  1. 自動呼び出し: オブジェクトの参照がゼロになると自動実行
  2. 決定論的: GCのタイミングに依存しない
  3. 伝播: 親オブジェクトのfini()が子オブジェクトに伝播

実装例

box DatabaseConnection {
    init { connection, transactions }
    
    fini() {
        // トランザクションをすべてロールバック
        for tx in me.transactions {
            tx.rollback()
        }
        // 接続を閉じる
        me.connection.close()
    }
}

// 使用例
{
    local db = new DatabaseConnection()
    db.connect("localhost:5432")
    // ... データベース操作 ...
}  // スコープを抜けると自動的にfini()が呼ばれる

💭 weak参照システム

循環参照の問題と解決

// 循環参照の例
box Parent {
    init { children }
    
    pack() {
        me.children = new ArrayBox()
    }
    
    addChild(child) {
        me.children.push(child)
        child.parent = me  // 循環参照!
    }
}

box Child {
    init { parent }
}

weak参照による解決

box Parent {
    init { children }
    
    pack() {
        me.children = new ArrayBox()
    }
    
    addChild(child) {
        me.children.push(child)
        child.parent = weak me  // weak参照で循環を防ぐ
    }
}

box Child {
    init { parent }  // weak参照として保持
    
    getParent() {
        // weak参照から通常参照を取得
        local p = strong me.parent
        if p == null {
            console.log("Parent has been deleted")
            return null
        }
        return p
    }
}

weak参照の特徴

  1. 自動null化: 参照先が削除されるとnullになる
  2. メモリリーク防止: 循環参照を断ち切る
  3. 明示的変換: strongで通常参照に変換

📊 メモリ管理パターン

1. 所有権パターン

box Container {
    init { items }  // Containerがitemsを所有
    
    pack() {
        me.items = new ArrayBox()
    }
    
    fini() {
        // itemsも自動的に解放される
        console.log("Container and all items released")
    }
}

2. 共有参照パターン

// 複数のオブジェクトで共有
local sharedData = new DataBox()

local viewer1 = new DataViewer(sharedData)
local viewer2 = new DataViewer(sharedData)

// sharedDataは両方のviewerから参照されている間は生存

3. 観察者パターン

box Subject {
    init { observers }
    
    pack() {
        me.observers = new ArrayBox()
    }
    
    attach(observer) {
        // weak参照で観察者を保持
        me.observers.push(weak observer)
    }
    
    notify() {
        // weak参照をチェックしながら通知
        local aliveObservers = new ArrayBox()
        
        for weakObs in me.observers {
            local obs = strong weakObs
            if obs != null {
                obs.update(me)
                aliveObservers.push(weakObs)
            }
        }
        
        // 死んだ参照を削除
        me.observers = aliveObservers
    }
}

🛡️ メモリ安全性保証

1. 二重解放防止

Arcにより、同じオブジェクトの二重解放は不可能。

2. Use-After-Free防止

参照カウントにより、使用中のオブジェクトは解放されない。

3. データ競合防止

Mutexにより、同時アクセスは自動的に同期される。

4. メモリリーク検出

// デバッグモードでメモリリーク検出
DEBUG = new DebugBox()
DEBUG.startTracking()

// ... プログラム実行 ...

print(DEBUG.memoryReport())
// 出力: 未解放オブジェクト一覧

🚀 ベストプラクティス

1. fini()の正しい使い方

box ResourceManager {
    init { resources }
    
    fini() {
        // 1. 子リソースから順に解放
        for resource in me.resources {
            resource.release()
        }
        
        // 2. 自身のリソースを解放
        me.cleanup()
        
        // 3. ログを残す(デバッグ用)
        console.log("ResourceManager cleaned up")
    }
}

2. weak参照の使い時

  • 親子関係: 子→親はweak参照
  • イベントリスナー: Subject→Observerはweak参照
  • キャッシュ: 一時的な参照はweak

3. メモリ効率的なコード

// ❌ 非効率
loop(i < 1000000) {
    local temp = new StringBox("temp")
    // tempが毎回作られる
}

// ✅ 効率的
local temp = new StringBox("")
loop(i < 1000000) {
    temp.set("temp")
    // 既存オブジェクトを再利用
}

📈 パフォーマンス考慮事項

1. 参照カウントのオーバーヘッド

  • 小さいが無視できない
  • ホットパスでは最小限に

2. Mutexロックの競合

  • Phase 9.75で一元化により改善予定
  • 細粒度ロックを避ける

3. fini()の実行コスト

  • 複雑なfini()は避ける
  • 非同期処理は避ける

🔮 将来の拡張

1. 世代別GC

参照カウントと世代別GCのハイブリッド検討

2. メモリプール

頻繁に生成・破棄されるBoxのプール化

3. コンパクション

メモリ断片化対策


関連ドキュメント: