Unity でのスキニング、バッチング、物理計算、ユーザースクリプト、パーティクルなどは CPU に依存します( x86 の SSE や、ARM の NEON など、 SIMD 部分に最適化しています )。
GPU はシェーダー、ドローコール、イメージエフェクトで使用されます。
大部分の問題 (80%) は少数の問題(20%)により引き起こされます。エディタープロファイラーを使用してもっとも問題となる関数コールをみつけて最初に最適化します。多くの場合、それらの重大な部分を最適化するだけで、全体的な実行速度を改善させることができます。
スクリプトが必要なときだけ実行されていることを確認してください。例えば、アクティブである必要がないオブジェクトを見つけて OnBecameVisible/OnBecameInvisible を使用して無効化してください。毎フレームごとに実行する必要がない場合コルーチンを使用します。
// すべてのフレームで何かを行います
void Update () {
}
//0.2 秒ごとに何かを行います
IEnumerator SlowUpdate () {
while (true) {
//何かを行います
yield return new WaitForSeconds (0.2f);
}
}
.NET System.Threading.Thread クラスを使用して重い処理は別スレッドにします。これによりマルチコア実行できますが UnityAPI はスレッドに完全には対応していません。バッファ入力や結果や読み込みはメインスレッドに割り当てします。
すべてのユーザーコードがプロファイラーに表示されるわけではありません。しかし Profiler.BeginSample および Profiler.EndSample を使用して必要なユーザーコードをプロファイラーに表示させることができます
Unity エディタープロファイラーは現時点では GPU データを表示できません。我々はハードウェア製造元と協力をしながらエディタープロファイラーに Tegra デバイスでは表示できるように進めています。
PowerVR はタイルベースディファードレンダラーであり、ドローコール毎の GPU タイミングを取得することは不可能です。しかしシーン全体の GPU 時間を取得するのに Unity のビルトインプロファイラーを使用できます( Xcode に結果出力する分)。現在 Apple ツールは GPU およびそのパーツがどれだけビジーかのみ伝達し、ミリ秒単位で知ることはできません。
PVRUniSCo によりシェーダーコードの中のシェーダー全体のサイクルを Windows および Mac ともに知ることができます。 しかし Apple ドライバの状況を正確には反映できていません。それでも簡易的な指標としては十分です。
Tegra では、NVIDIA から最高級のパフォーマンス測定ツールが提供されていて実現したいことのすべてができます - ドローコール毎の GPU 時間、シェーダー毎のサイクル、強制 2x2 テクスチャ、Null ビュー四角形、で Windows、OSX、Linux にて動作します。PerfHUD ES はコンシューマデバイスで上手く動作しないため NVIDIA の development board が必要です。
Qualcomm により優秀な Adreno Profiler (Windows のみ) が提供されていて Windows のみですが、タイムライングラフ、フレームキャプチャ、API コール、シェーダーアナライザ、ライブ編集の機能があります。
内部プロファイラーによりモジュール毎のよい概要が得られます:
Unity プロファイラーが使用するポートは:
+\tMulticastPort : 54998 +\tListenPorts : 55000 - 55511 +\tMulticast (ユニットテスト) : 55512 - 56023
ネットワークノードの中からアクセスできる必要があります。つまりプロファイリングを行うデバイスはプロファイラーを有効にして Unity エディター上でマシンのポートをみることができる必要があります。
Unity メモリーと Mono メモリーの2種類があります。
Mono メモリはスクリプトオブジェクト、Unity オブジェクトのラッパー(ゲームオブジェクト、アセット、コンポーネント、その他)をハンドリングします。ガベージコレクションにより、利用可能なメモリへの割り当てができなかった場合、または System.GC.Collect() コールの場合、クリーンアップを行います。
メモリはヒープブロックに割り当てされます。ヒープブロックはアプリが閉じられるまで Mono に保持されます。すなわち Mono は使用メモリを OS に対して開放しません (Unity 3.x)。特定の量のメモリを割り当てると Mono のために予約されて OS では利用可能ではありません。リリースしたときも Mono で内部的に利用可能となるのみで OS にとつては利用可能ではありません。プロファイラーのヒープメモリは増加するのみで、減ることがありません。
もしシステムが割り当てたヒープブロックに新しいデータを当てはめる領域が十分にない場合、Mono により “GC” がコールされ、新しいヒープブロックを割り当てできるようになります(例えばフラグメンテーションにより)
ヒープのセクションがありすぎるということは Mono メモリを使い切ったことを意味します(フラグメンテーションまたは重い処理により)。
System.GC.GetTotalMemory
を使用して Mono でメモリ使用量の合計を取得します。
一般的なアドバイスとしては、できるかぎり割り当ては小さくします。
Unity メモリはアセットデータ(テクスチャ、メッシュ、音声、アニメーション、等)、ゲームオブジェクト、エンジン内部処理(レンダリング、パーティクル、物理計算、その他)をハンドリングします。
Profiler.usedHeapSize
を使用して Unity メモリ使用量の合計を取得します。
ツールはまだ存在しませんが次のものが使用できます。
また、Unity API を呼び出して自身でツールを作成することができます:
FindObjectsOfTypeAll (type : Type) : Object[]
FindObjectsOfType (type : Type): Object[]
GetRuntimeMemorySize (o : Object) : int\\t
GetMonoHeapSize
GetMonoUsedSize
Profiler.BeginSample/EndSample
- 自分で実装したコードをプロファイリングUnloadUnusedAssets () : AsyncOperation
System.GC.GetTotalMemory/Profiler.usedHeapSize
ロードされたオブジェクトへの参照 - これを知る方法はありません。回避方法としてパブリック変数の参照を Find することです。
OnGUI()
は使用しないこと: 毎フレーム数回実行され、ビューを完全に書き換えることになり、ガベージコレクション実行を必要とする大量のメモリ割り当てをコールしてしまいます。System.GC.Collect()
という .Net 関数を使用可能です。どこかの時点でゲームはメモリ不足 “out of memory” でクラッシュするかもしれませんが、理論的には十分なはずです。これが発生した場合、通常のゲームメモリ使用量と今回割り当てされたメモリの大きさを比較します。もし数字にかなり差がある場合、メモリの急増が発生しています。これの要因としては: