【Unity】アプリを極限まで最適化する

概要

基本的な最適化については「Unityアプリを高速・安定化するために見直すべき事を9選まとめてみた|Qiita」で網羅的に解説されています。
この記事は、このアプリ(Weather・天気予報アプリ)で使われている特殊な最適化手法です。

☆本記事に書かれている内容ーーーー
 ・不要な機能の無効化
 ・メモリ解放
 ・GPU/ストレージの最適化
--------------ーーー


不要な機能の無効化

Physics(物理演算)

物理演算機能は必要ないのでオフにします。
プログラムのStart関数を編集します。2Dの場合は”Physics2D.autoSimulation = false;”を使います。両方書く必要はありません。

void Start()
{
    Physics.autoSimulation = false;
    Physics2D.autoSimulation = false; //2Dの場合はこちらを記載
}

Audio(音声)

音声もオーバーヘッドの原因となるので使いません。図1に示すように、”Project Settings>Audio”でAudioManagerを開きます。

図1.Audioの設定場所

“Disable Unity Audio”にチェックを入れます(図2)。

図2.Unityのデフォルトオーディオ無効化



メモリの解放

スクリプト

天気予報プログラムでは、図3に示すように、画像をダウンロードして読み込んでいます。

図3.テクスチャを動的に取得している

これをそのまま実装してみましょう。
プログラムを立ち上げて放置。タスクマネージャを観察すると、数ギガバイト単位でVRAMが占領されていることが発覚します(図4)。

図4.GPUメモリ使用量が徐々に増加し、PCがクラッシュする。

原因は一つで、画像データのキャッシュが解放されていないためです。

Unityは動的に取得した、テキストデータ(JSON、xml)・画像(png、jpg)ファイルをResourcesに振り分けます。さらに、変数値を変更したとき、古い値をそのままメモリ上で保持しているケースがあります。
したがって、これらのキャッシュは明示的に開放する必要があります。実行は数分に一度で、基本はどこに書いても大丈夫です。ただし、ガベージコレクションやUnloadUnusedAssetsは重いため、間違ってもUpdate関数の中から呼び出さないようにしてください(※)。

//メモリを解放する
Resources.UnloadUnusedAssets(); GC.Collect();

※UnloadUnusedAssetsは実行に0.3~2秒かかります。AsyncOperationなので、処理が終わるまで待たされます。


ここでビルドしても十分に低負荷ですが、さらにパフォーマンスを切り詰めたいので、次節以降の設定も適用します。
最終的に、ここから図5のように、CPU・GPU負荷が半分以下になります。

図5.次節以降の設定前後のパフォーマンス変化


GPU/ストレージの最適化

Quality(描画品質)

Project Settings>Quality。
ここは、Very LowやLowを参考に、ギリギリまで落とします。

適当な設定はアプリごとに違うため、自分で調べてほしいのですが、一点だけ落とし穴があります。

垂直同期の設定について、Don’t Sync(同期しない)にするというのが定説とされています。
しかし、自作PCのようにグラフィックボードを自前で揃えている端末の場合、ディスプレイとGPUのfpsが合わないことが稀によくあります

このとき、GPUにもCPUにも結構な負荷がかかります。高性能PCであればあるほど、傾向は顕著です。
これを回避するため、垂直同期は”Every V Blank”もしくは”Every Second V Blank”に設定します。

図6.垂直同期の設定

もしくは、”Don’t Sync”を選択し、スクリプトでフレームレートを設定します。この場合はStart関数に次のコードを書きます。

Application.targetFrameRate = 60;

とくに、iOS向けアプリケーションの場合はデフォルトでフレームレートが30fpsに設定されているため、Android版と比べてなぜかカクカクするという現象が起こる場合があります。
したがって、iOS版での展開を視野に入れるなら、下の方法一択です。


Canvas(UIの分割)

要素に一か所でも変更が与えられると、Canvasは子のUIすべてに対してメッシュを再生成します。何の変化も無いUIを実現するのは難しいので、変化がある動的なCanvasと、変化のない静的なCanvasは分離します

ビルドの選択

Windowsの場合、スクリプト・バックエンドとして、MonoとIL2CPPを選択できます(図7)。Project Settings>Player>Configurationで確認可能です。

図7.Unityのスクリプト・バックエンド

IL2CPPの方がプログラムの動作は高速です。しかし、ファイルサイズには、370MB(IL2CPP)に対し、58.7MB(mono)と実に6倍以上の差が生じました。

図8.mono/IL2CPPのビルドサイズは6倍以上違う

今回のプログラムの場合、そこまでシビアな実行速度差を求めないので、monoを選択します。ビルド時間もIL2CPPの方が長くかかるのも大きな理由です。

再圧縮

Android向けのビルドで、さらにファイルサイズを削りたい場合、図9のようにapk(aab)の拡張子を一度、zipに変えます。

図9.apkのzip化

このファイルを展開し、中身をもう一度「7zip」でzip形式に圧縮します(図10)。

図10.再圧縮

こうして出来たzipファイルの拡張子を、もう一度apk(aab)に戻します。すると、容量が1MB近くも減ったことが確認できます(図11)。

図11.容量が減った

どうして容量が減ったのかは全く分かりません・・・

作成者: rarafy

2013年くらいからUnityを触っているかもしれません。 特に書くこともありませんが、趣味は部屋の掃除です。

コメントする

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です