unity-performance について
unity-performanceは、フレーム落ちやメモリ割り当てを調べるUnity開発者向けのコードレビュー用スキルです。明確な性能上の懸念を優先し、可能性の高い問題と根拠の乏しい微細な最適化を区別します。
主な機能
- 01高頻度の検索や更新ループを検出
- 02割り当てとプーリングの候補を特定
- 03見えにくい実行時コストを説明
- 04確度と影響度で指摘を整理
活用シーン
- 01Unityコードの性能リスクをレビュー
- 02フレーム落ちやカクつきを調査
- 03オブジェクトプーリングと割り当て削減を計画
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ besty0728/ unity-skills --skill unity-performanceインストール後、Claude Code で/unity-performanceを入力して読み込まれたか確認します。
詳細
このモジュールのスキルを呼び出す前に: 名前や説明から推測したパラメーターを使ってスキルを呼び出そうとしている場合は、いったん停止し、先にこのファイルを読むか、
GET /skills/recommend?includeSchema=trueでスキーマを取得してください。recommend/schema からすでにパラメーター定義を取得している場合は、そのまま dryRun に進めます。
トリガー
- パフォーマンスのレビュー
- フレーム落ちの診断
- メモリ割り当ての削減
- プーリング/最適化の計画
- パフォーマンスのレビュー、フレーム落ちやカクつきの診断、メモリ割り当ての削減、オブジェクトプール/最適化の計画
Unity のパフォーマンスに関する危険信号
Unity で起こり得るパフォーマンス上の問題を高い精度でレビューするには、このスキルを使用します。推測に基づくマイクロ最適化ではなく、危険信号に注目してください。
確認項目
- 関係のない
Update/LateUpdate/FixedUpdateループが多すぎる - ホットパスで
Find、GetComponent、Camera.main、タグ検索を繰り返している - プーリングに適した
Instantiate/Destroyが頻繁に実行されている - 回避可能なフレームごとのメモリ割り当て:
- LINQ
- 文字列フォーマット
- クロージャ
- ボックス化
- ランタイムのホットパスでリフレクションを使用している
- エディター専用の高コストなヘルパーがランタイムコードに混入している
- 物理演算、アニメーション、UI の更新頻度が適切でない
隠れたコスト:可能性 ≠ 実際の処理
一見「無料」に思えるものが、実際には高コストになる直感に反する落とし穴が 3 つあります。これらのコストは、実際に処理が行われたかどうかではなく、処理が行われる可能性に対して発生します。そのため、プロファイラーで直接検出することはほとんどできません。
書き込み権限は、書き込みを行わなくてもコストがかかる
Update 内で transform.position を変更できるコンポーネントは、その分岐が実行されなくてもコストを負担します。ダーティフラグやシリアライゼーションシステムは、書き込み権限を毎フレームのポーリングが必要な理由として扱うためです。同様に、実行時に一度も変更されない [SerializeField] フィールドも、シリアライゼーションの処理経路に残ります。解決策は分岐を厳しくすることではなく、権限を取り除くことです。まれにしか必要とされない書き込み処理を別のコンポーネントに分離し、必要になったときだけ AddComponent してください。出典:NetcodeSamples/HelloNetcode/2_Intermediate/07_Optimization/Optimization.md — 「コンポーネントに書き込む可能性があるシステムは、実際に書き込むかどうかに関係なく、常にシリアライズする必要がある」。
連続するシード値は相関した乱数列を生成する
N 個の RNG インスタンスに baseSeed + i をシードとして設定すると、N 個の類似した乱数列が生成されます。巡回経路が揃い、スポーン位置の揺らぎが偏り、戦利品の抽選結果が集中します。シード設定の前にインデックスをハッシュしてください:
// Wrong — N correlated streams
for (int i = 0; i < N; i++) rngs[i] = new System.Random(baseSeed + i);
// Correct — hash decorrelates adjacent seeds
for (int i = 0; i < N; i++)
rngs[i] = new System.Random((int)((uint)baseSeed * 2654435761u ^ (uint)i));
Unity.Mathematics.Random.CreateFromIndex(i) はこれを内部で適用するため、数学パッケージが利用可能な場合はこの方法が推奨されます。出典:Dots101/Entities101/Assets/HelloCube/3. Prefabs/SpawnSystem.cs:37-39 およびそのコメント。
リリースビルドでもログはデフォルトで出力される
Debug.Log は Player ビルドで除去されません。引数が呼び出し元で省略されるのは、[Conditional("UNITY_EDITOR")] が付与されたメソッド(Debug.DrawLine など)だけです。つまり、文字列補間やヘルパー呼び出しを含むログ行は、リリースされたゲーム内でも毎フレーム実行されます:
// Wrong — GetPlayerInfo() and string interpolation execute in release
Debug.Log($"Player {GetPlayerInfo()} at {Time.time}");
// Better — guard the whole expression
if (Debug.isDebugBuild) Debug.Log($"Player {GetPlayerInfo()} at {Time.time}");
これは前述の「書き込みの可能性」のルールと同じ原則です。ランタイムは、実際の処理だけでなく、処理が行われる可能性に対してコストを負担します。
出力形式
- 確認済みの危険信号
- 可能性の高い危険信号
- 今すぐ行う価値のある変更
- 今すぐ行う価値のない変更
- 期待できる効果の分類:明瞭さ/フレーム時間/GC/スケーラビリティ
ガードレール
モード:ドキュメントのみ — REST スキルによる制限はありません。どの動作モード(Approval/Auto/Bypass)でも自由に読み込めます。
- 重大なホットスポットがない限り、大規模なリファクタリングを推奨しないでください。
- ホットパスが実在するのでない限り、シンプルなコードを読みにくい「最適化済み」コードに置き換えないでください。