Version: 2019.4
言語: 日本語
プロファイリング
コルーチン

メモリ

メモリの消費状況はパフォーマンスの状態を示す重要な指針です。これは、低性能モバイルデバイスなど、メモリ資源の少ないプラットフォームにおいては特に重要です。

メモリ消費のプロファイリング

Unity におけるメモリ問題の診断には、Unity の Bitbucket から入手可能な オープンソースのメモリ可視化ツール が最適です。このツールの統合は簡単で、関連付けられたリポジトリをダウンロードし、そこに含まれる Editor フォルダーをプロジェクトに配置するだけで行えます。

このツールは、5.3 以降のどのバージョンの Unity でも使用できます。IL2CPP を用いてビルドされたアプリケーションに添付することで、ネイティブコードおよびマネージコードのメモリ消費に関する豊富な情報を取得することができます。

このツールを使用するには IL2CPP スクリプティングバックエンドでプロジェクトをビルドし、それを適切なデバイスにデプロイします。Unity の通常のエディター内 CPU プロファイラーを添付し、Window > MemoryProfilerWindow の順に移動し、Take Snapshot を選択してください。

データが収集されて Unity エディターに送信される間、デバイス上のアプリケーションが少しの間一時停止します。その後 Unity エディターが、受領したデータを解析するために一時停止しますが、これに著しく時間が掛かる場合があります。メモリ負荷が特に高いアプリケーションの場合、トレースの解析に 10 - 30 分かかることもあります。

この解析と読み込み処理が行われる間、しばらく待機します。

このスクリーンショットは iOS デバイスで実行される Standard Assets Scene から取ったものです。消費メモリの 4 分の 3 が、飛行機の機体に関わる 4 つの非常に大きなテクスチャに使用されていることが確認できます。

この表示は拡大して見ることができます。アプリケーション内の各ボックスをクリックすると、詳細情報が表示されます。

重複するテクスチャの特定

メモリの問題でよくあるもののひとつは、メモリ内におけるアセットの重複です。テクスチャはプロジェクト内で最もメモリ負荷の高いアセットであるため、テクスチャの重複は Unity プロジェクトで最も一般的なメモリ問題のひとつとなっています。

重複したアセットは、同じアセットから読み込まれたと思われる同タイプで同サイズの 2 つのオブジェクトを見付けることで特定することができます。Memory プロファイラーの Detail のセクションにある Name フィールドと InstanceID フィールドを確認して、同一であると思われるオブジェクトを探してください。

Name フィールドは、オブジェクトの読み込み元であるアセットファイルの名前から来ています。通常これは、ファイルのパスや拡張子なしのファイル名となっています。InstanceID フィールドは、Unity ランタイムによって割り当てられた内部的な識別番号を示します。この番号は、Unity ゲームの 1 回の実行において固有の番号です(1)。

こちらの画像で上記の問題の一例を確認できます。左右の画像はそれぞれ、Unity 5.4 の Memory プロファイラーの Detail セクションのスクリーンショットです。ここには表示されているアセットは、メモリ内に別々に読み込まれた 2 つのテクスチャです。これらのテクスチャは名前とサイズが全く同じなので、重複テクスチャである可能性が推測されます。プロジェクトの “Assets” フォルダーを調べると、 wood-floorboards-texture という名前のアセットが 1 つしかないことが判明するかもしれません。そうであれば、このアセットは重複している可能性が非常に高くなります。

メモリ内の各 UnityEngine.Object はそれぞれ固有のインスタンス ID を持っています。この ID はオブジェクトの作成時に割り当てられるものです。この 2 つのテクスチャは異なる ID を持っているので、それぞれが、メモリに読み込まれた 2 つの別々のテクスチャデータを表しているということは確かです。

ファイル名とアセットサイズが同じでインスタンス ID が異なるので、これらの 2 つのオブジェクトは、メモリ内で複製された 1 つのテクスチャを表しているということが確かです。(ノート: 同一のファイル名を持つテクスチャがプロジェクト内にある場合は、これは断定できませんが、このようにファイルサイズが全く同じである場合は、その可能性が非常に強いといえます。)

アセットバンドルとアセットの重複

メモリ内でテクスチャやアセットの重複が引き起こされる最もよくある原因は、アセットバンドルの不適切なアンロードです。この問題に関しては、Unity の アセットバンドルとリソースに関するガイド を参照してください。重要なセクションは Managing loaded Assets です。

イメージバッファ、イメージエフェクト、レンダーテクスチャの使用メモリの調査

メモリ可視化ツールでは、イメージエフェクトやレンダーテクスチャオブジェクトへのレンダーバッファの供給に必要なメモリを視覚的に確認することもできます。

上のスクリーンショットは、Unity の Cinematic Image Effect がいくつか適用された単純なシーンから取ったものです。これらのイメージエフェクトは、演算処理を実行するために一時的なレンダーバッファの割り当てを行います。中でも Bloom エフェクトは、徐々にサイズの減少するいくつかのバッファーを割り当てます。Retina iOS デバイスは高解像度なため、このような一時的バッファの使用メモリが、プロジェクトのその他全ての部分の合計使用メモリを大幅に凌ぐ量となります。

また iPad Air 2 は 2048 x 1536 でレンダリングを行います。これは、最新のコンソールや PC 向けプロジェクトで一般的に目標とされる解像度 1080p を超えるものですが、タブレットで実行されています。フルスクリーンの一時的なレンダーバッファは、バッファの形式によって 24 または 36 MB のメモリをフルに使用します。レンダーバッファーのピクセル寸法を半分にすると、これを 75% 削減できます。この方法は多くの場合、ビジュアルのクオリティをそれ程下げずに行うことができます。

一時的レンダーバッファやその他 GPU リソースのイメージエフェクトによる使用を最適化する方法のひとつは、様々な計算を全て同時に実行する “Uber” イメージエフェクトを 1 つ作成することです。バージョン 5.5 以降の Unity を使用する場合は、新しい UberFX (github から入手可能) パッケージの使用が可能です。このパッケージは、調整可能な “uber” (素晴らしい) イメージエフェクトを提供します。このエフェクトは Cinematic Image Effect が提供する全ての処理を、個々の Image Effect を使用するよりも少ないオーバーヘッドで実行することができます。

プロファイリング
コルーチン