# プロファイラー出力の分析

> Investigate common startup and runtime performance issues by analyzing Profiler traces.

アプリケーションをプロファイルする時に、いくつかの一般的な問題が発生する可能性があります。このページでは、一般的なパフォーマンス問題の原因を調査する方法について説明します。

## 起動時の出力の分析

起動時間のプロファイリング出力を確認する場合、主に調査すべきメソッドは 2 つあります。`UnityInitApplicationGraphics` と `UnityLoadApplication` です。プロジェクトの設定、アセット、コードによる起動時間への影響に関しては、主にこの 2 つのメソッドが原因となります。

**注意**アプリケーションの起動時間はプラットフォームによって異なります。ほとんどのプラットフォームでは、起動は [スプラッシュスクリーン](/engine/6000.0/manual/unity-editor/editor-features/comp-manager-group/class-player-settings/splash-screen.md) の表示中に行われます。


**iOS デバイスで実行したサンプル Unity プロジェクトの Instruments の出力:**
![](/api/media?file=/engine/6000.0/media/images/UnderstandingPerformanceinUnity-ProfilingSection_image_0.png)

上の iOS デバイスで実行したサンプル Unity プロジェクトの Instruments の出力のスクリーンショットで、プラットフォーム別の `startUnity` メソッド内の、`UnityInitApplicationGraphics` メソッドと `UnityLoadApplication` メソッドに注目してください。

`UnityInitApplicationGraphics` は多くの内部機能を実行します。例えばグラフィックスデバイスの設定や、多くの Unity 内部システムの初期化などです。また、[リソースシステム](/engine/6000.0/manual/analysis/understanding-performance/resources-folder.md) に含まれる全てのファイルのインデックスをロードすることで、リソースシステムの初期化も行います。

Unity の [リソースシステム](/engine/6000.0/script-reference/unity-engine/resources.md) には、プロジェクトの `Assets` フォルダー内の `Resources` フォルダーにあるデータ内の全ての [アセットファイル](/engine/6000.0/manual/working-in-unity/assets-and-media/asset-workflow/asset-types.md) が含まれます。これには、`Resources` フォルダーの子フォルダーにある全てのファイルが含まれます。したがって、リソースシステムの初期化に掛かる時間は、アプリケーションのプロジェクトの `Resources` フォルダー内のファイル数に応じて直線的に増加します。

`UnityLoadApplication` にはプロジェクトの最初のシーンをロードして初期化する (複数の) メソッドが含まれます。これには最初のシーンの表示に必要なデータのデシリアライゼーションとインスタンス化 (シェーダーのコンパイリング、テクスチャのアップロード、ゲームオブジェクトのインスタンス化など) が含まれます。また、Unity は最初のシーン内の全ての `MonoBehaviour` の `Awake` コールバックを実行します。

上記のようなプロセスになっているということは、つまり、プロジェクトの最初のシーン内の `Awake` コールバック内に長時間掛かるコードが 1 つでもある場合、そのコードが原因でプロジェクトの最初の起動時間が長くなっている可能性があるこということです。これを解決するには、時間の掛かるコードを削除するか、そのコードをアプリケーションのライフサイクル内の他の場所で実行するようにする必要があります。

## ランタイムの出力の分析

最初の起動時間の後にキャプチャされたプロファイリング出力に関しては、主に注目すべきは `PlayerLoop` メソッドです。これは Unity のメインループで、中にあるコードが 1 フレームに 1 回実行されます。


**サンプル Unity プロジェクトの Instruments の出力:**
![](/api/media?file=/engine/6000.0/media/images/UnderstandingPerformanceinUnity-ProfilingSection_image_1.png)

上のスクリーンショットは、`PlayerLoop` 内でパフォーマンスに最も影響を与えるいくつかのメソッドを示しています。**注意**`PlayerLoop` 内のメソッドの名前は Unity のバージョンによって異なる可能性があります。

`PlayerRender` は、Unity のレンダリングシステムを実行するメソッドです。これにはオブジェクトのカリング、動的バッチの計算、GPU への描画指示のサブミットなどが含まれます。イメージエフェクトや、レンダリングベースのスクリプトコールバック (例えば、[OnWillRenderObject](/engine/6000.0/script-reference/unity-engine/mono-behaviour/on-will-render-object.md)) も全てここで実行されます。基本的に、プロジェクトがインタラクティブな時に最も CPU 時間を消費するのがこのメソッドです。

`BaseBehaviourManager` はテンプレート化された 3 つのバージョンの `CommonUpdate` を呼び出します。これらは、現在のシーン内のアクティブなゲームオブジェクトに添付された `MonoBehaviour` 内の特定のコールバックを実行します。

* `CommonUpdate<UpdateManager>` は `Update` コールバックを呼び出します。
* `CommonUpdate<LateUpdateManager>` は `LateUpdate` コールバックを呼び出します。
* `CommonUpdate<FixedUpdateManager>` は、物理演算システムにチェックマークが入っている場合に `FixedUpdate` を呼び出します。

調査する上で基本的に最も便利なメソッドファミリは `BaseBehaviourManager::CommonUpdate<UpdateManager>` です。これが Unity プロジェクト内で実行される大部分のスクリプトコードのエントリーポイントだからです。

他にも、調査に役立つメソッドがいくつかあります。

* `UI::CanvasManager` は、プロジェクトが [UGUI システム](https://docs.unity3d.com/Packages/com.unity.ugui@latest) を使用している場合に、いくつかの異なるコールバックを実行します。これには Unity UI のバッチ計算やレイアウト更新が含まれます。プロファイラーに `CanvasManager` が表示される場合、その原因として最もよく見られるのは、この 2 つの処理です。
* `DelayedCallManager::Update` は [コルーチン](/engine/6000.0/manual/scripting/object-oriented-development/coroutines.md) を実行します。
* `PhysicsManager::FixedUpdate` は PhysX 物理演算システムを実行します。これは主に PhysX の内部コードを実行することによって行われます。`Rigidbody` や `Collider` など、現在のシーン内にある物理演算オブジェクトの数は、PhysX の内部コードに影響します。物理演算ベースのコールバックもここに表示されます。具体的には、`OnTriggerStay` と `OnCollisionStay` です。

プロジェクトが 2D 物理演算を使用している場合、それは、一式の類似したコールとして `Physics2DManager::FixedUpdate` の下に表示されます。

## スクリプトメソッドの分析

スクリプトが IL2CPP を用いてクロスコンパイルされてプラットフォーム上で実行されている場合、`ScriptingInvocation` オブジェクトの含まれる出力ラインを探してください。そこが、Unity の内部ネイティブコードが、スクリプトコードを実行するためにスクリプトランタイムへ遷移している箇所です。**注意**技術的には、Unity が IL2CPP 経由で実行した後は、C# コードもネイティブコードとなります。ただしこのクロスコンパイルコードは、主に IL2CPP ランタイムフレームワークでメソッドを実行しており、手書きの C++ とは類似しません。


**サンプル Unity プロジェクトからの出力:**
![](/api/media?file=/engine/6000.0/media/images/UnderstandingPerformanceinUnity-ProfilingSection_image_2.png)

上のスクリーンショットで、`RuntimeInvoker_Void` ラインの下にネストされたメソッドは、1 フレーム毎に 1 回実行されるクロスコンパイル済み C# スクリプトの一部です。

出力ラインの名前は、元のクラス名、下線、元のメソッド名の順で連なった形になっています。このサンプルの出力では、`EventSystem.Update`、`PlayerShooting.Update`、その他いくつかの `Update` メソッドが確認できます。これらは、ほとんどの `MonoBehaviours` 内に見られる、Unity の標準の `Update` コールバックです。

これらのメソッドを展開すると、その中のどのメソッドが CPU 時間を消費したかを確認できます。これは、プロジェクト内、Unity API 内、C# ライブラリコード内のその他のスクリプトメソッドに関しても同様に行えます。

上の出力からは、`StandaloneInputModule.Process` メソッドが 1 フレーム毎に 1 回、UI 全体にレイキャストを行っていたことが確認できます。このメソッドは、何らかのタッチイベントが UI 要素上をホバリングしたり要素をアクティベートしたりしていたかどうかを検知します。全ての UI 要素に対してメソッドを繰り返し、マウスの位置がその境界矩形内にあるかどうかをテストすると、高いリソース負荷が掛かります。

## アセットの読み込み

CPU の出力内でアセットのロードを特定することもできます。アセットのロードを示す主要なメソッドは `SerializedFile::ReadObject` です。このメソッドは特定のファイルからのバイナリデータストリームを、`Transfer` という名前のメソッドによって実行される Unity のシリアル化システムに接続します。`Transfer` メソッドは、テクスチャ、MonoBehaviour、パーティクルシステムを始めとする全てのアセットタイプに見られます。


**シーンのロードの出力:**
![](/api/media?file=/engine/6000.0/media/images/UnderstandingPerformanceinUnity-ProfilingSection_image_3.png)

上のスクリーンショットは、Unity がシーンをロードした出力です。シーンをロードすると、Unity はシーン内の全てのアセットを読み込み、デシリアライズします。これは、`SerializedFile::ReadObject` の下にあるさまざまな `Transfer` メソッドのコールによって示されます。

ランタイムにパフォーマンススタッターが発生し、パフォーマンス出力で `SerializedFile::ReadObject` がかなりの時間を費やしたことが示されている場合は、アセットのロードによってフレームレートが減少したことを意味します。**ノート:** `SerializedFile::ReadObject` は通常、`SceneManager`、`Resources`、または AssetBundle API がアセットの同期的ロードをリクエストすると、メインスレッドに表示されます。

このパフォーマンススタッターを解決するには、アセットのロードを非同期にする (重い `ReadObject` コールがワーカースレッドに移される) か、一部の重いアセットをプリロードしてください。

`Transfer` コールは、Unity がオブジェクトをクローン (複製) する場合にも現れます (出力内では `CloneObject` メソッドによって示されます)。`Transfer` への呼び出しが `CloneObject` コールの下に表示される場合、Unity は該当アセットをストレージからロードしていません。代わりに、Unity は古いオブジェクトのデータを新しいオブジェクトに送信します。Unity はこれを行うために、古いオブジェクトをシリアル化し、その結果のデータを新しいオブジェクトとしてデシリアライズします。
