今回はアセットのUnloadとDestroyの使い分けと、アセットの運用についてです。
- 基本的にはアセットの開放はResources.Unloadで可能
- Resources.Unloadで開放出来ないケース
- インスタンス化したアセットの開放はDestroy
- 大抵の場合はUnloadUnusedAssets
基本的にはアセットの開放はResources.Unloadで可能
Resources.Unloadはアセットを開放する事が出来ます。このアセットとは、例えばProfilerのMemoryの項目でAssetsと表示される項目が該当します。
Resources.Unloadはソコソコ強力で、Projectビューでアセットと認識している物は大体開放することが出来ます。
Resources.Unloadで開放出来ないケース
それ以外の項目、NotSavedやSceneMemoryに格納される、インスタンス化したオブジェクト群はResources.Unloadでは開放する事が出来ません。これは、実行時に値を変更したMeshやMaterialや動的に生成したTexture、Prefab等が該当します。
また、アンロードされたリソースはUnityのリソースマネージャーから開放され、「Instance IDが再度アクセスするまで」破棄されます。つまり、解放後即座にアクセスされた場合開放されていないように見えます。
Instance IDが再度アクセスするまで破棄するとは、少し表現が難しいのですが、Resources.Unloadが破棄するのは、あくまでInstance IDが参照するアセットなので、再度アセットに対して読込が走れば、表示されます。このため、Resourcesが複数の場所から参照されていた場合、まるで破棄されないような挙動になります(実際には破棄され、再読込が走るっぽいです)
この挙動は、ResourcesからTextureを読み込み後破棄、RawImageをEnable/disableすると確認出来ます。
なお、Unloadが開放するのは指定したアセットのみです。
つまり、Materialを開放したからと言って、Materialが参照するテクスチャ群を開放する訳ではありませんし、Materialが参照するShaderは開放されません。
同様にSpriteをUnloadしたからと言って、Textureを開放してくれる訳ではありません。
インスタンス化したアセットの開放はDestroy
NotSavedやSceneMemoryの項目に格納される、インスタンス化したアセットに関しては、Destroyで開放します。
もしエディタで動作させる場合、DestroyImmediate(オブジェクト, true)が必要になるかもしれません。但し、この処理はエディタで動かした場合「ファイルを消す」ので、実際に使用する場合には注意が必要です。(正確には、SetDirtyするまで消えないっぽいですが)
大抵の場合はUnloadUnusedAssets
パフォーマンス的に問題が無いのであれば、Resources.UnloadUnusedAssetsをとりあえず使っておけば問題は無いはずです。
このメソッドを実行すると、「未使用な」アセットを開放します。
この「未使用な」というのが少し曲者で、static fieldやfield等から参照している等の他に、インスタンス化する前のPrefab等から参照していた場合も「使用中」とマークされます。そのため、インスタンス化したGameObjectを破棄した後も、Prefabが残っている場合は参照するアセットが開放されないといったケースは有りえます。
またマニュアルに依るとスクリプト実行スタックは確認していないらしく、アセットを破棄後に再ロードが走るので、開放されないように見えるどころか、余計な負荷が走るかもしれません。
なお、以前のResources.UnloadUnusedAssetsは同期で処理を行っていたので、コレを行うと少しの間ゲームが停止してしまう問題がありましたが、現在は非同期で動作しており、あまりゲームを止める心配がありません。
但し、非同期で動作するため、連続して呼出すると何らかの問題が起こるかもしれません。