【Unity】Addressableアセットシステムのメモリ管理の仕組み

UnityのAddressableアセットシステムのメモリ管理の仕組みについてまとめました。

Unity2019.2.10
Addressable1.3.8

はじめに

この記事ではAddressableアセットシステムのメモリ管理の仕組みについてまとめます。
Addressableの概念や基礎知識についての説明はこの記事では省略しますが、
以下の記事にまとめていますので、必要に応じて参照してください。

light11.hatenadiary.com

また、ロードやアンロードの基本的なやり方については以下の記事にまとめています。

light11.hatenadiary.com

本記事はこれらの知識を前提とします。

ロードとリリース(アンロード)をペアにするのが基本

さてAddressableは参照カウントでリソースのロード・アンロードを管理しています。
Addressables.LoadAssetAsync()などでロードがリクエストされると参照カウントがインクリメントされ、
Addressables.Release()などでリリース(アンロード)がリクエストされるとデクリメントされます。

// 参照カウントがインクリメントされる
var handle = Addressables.LoadAssetAsync<GameObject>("Example");

// 参照カウントがデクリメントされる
Addressables.Release(handle);

そして参照カウントが1以上になった時にアセットがロードされて、0になった時にアンロードされます。

以上のことから、当然ですが「ロードしたものは必ずリリースする」というのが大原則となります。
ただし明示的にリリースしなくてもUnityが自動でやってくれるケースがあったりするので、このあたりを以下でまとめます。

GameObjectのリリースタイミング

Addressableを使ってGameObjectをインスタンス化する方法は大きく分けて二つあります。

一つ目はAddressables.LoadAssetAsync()などを使ってロードした後にGameObject.Instantiate()をする方法です。

var handle = Addressables.LoadAssetAsync<GameObject>("Example");
await handle.Task;
Instantiate(handle.Result);

この方法を使う場合は前節で説明したように、Addressables.Release()をすることでリリースされます。

GameObjectを生成する二つ目の方法としてAddressables.InstantiateAsync()を使う方法があります。

var handle = Addressables.InstantiateAsync("Example");

この場合、生成されたGameObjectが所属するシーンが破棄されると、それに連動してリリースが行われます。
つまり明示的にリリースしなくてもアセットがアンロードされます。
明示的にGameObjectの破棄と参照カウントのデクリメントを行う場合にはAddressables.ReleaseInstance()を使います。

ちなみにこのAddressables.ReleaseInstance()の引数にはAsyncOperationHandleかインスタンス自身のどちらかを渡しますが、
Addressables.InstantiateAsync()trackHandleという引数を持っていて、
これにfalseを渡すとAsyncOperationHandleでしかリリースができなくなります。
(使いどころはいまいちわかっていません)

シーンのアンロードタイミング

Addressableを使う場合、シーンはAddressables.LoadSceneAsync()を使ってロードします。

Addressables.LoadSceneAsync("ExampleScene");

こうしてロードしたシーンはAddressables.UnloadScene()を使ってアンロードできます。

ただし、他のシーンをSingleモードで読み込んだ場合には読み込まれる前に存在していたシーンは自動的にアンロードされます。

その他明示的なリリースが必要なもの

Addressables.LoadResourceLocationsAsync()とAddressables.GetDownloadSizeAsync()は、
明示的なリリースが行われるまでデータを保持し続けます。

よって、不要になった時点でこれらのAsyncOperationHandleに対してAddressables.Release()する必要があります。

自動的に解放されるもの

Addressables.DownloadDependenciesAsync()とかAddressables.UnloadScene()といったメソッドは
戻り値としてAsyncOperationHandleを返すものの、AsyncOperationHandle.Resultとして受け取るものがありません。

このようなAsyncOperationHandleを返すメソッドにはautoReleaseHandleというが用意されています。
これをtrueにすると処理が終わった後にHandleが自動的にリリースされます。

参照カウントを見る

さてこのようにしてインクリメント/デクリメントされる参照カウントを可視化するためにはEvent Viewerを使用します。
これについては以下の記事にまとめていますので、必要に応じて参照してください。

light11.hatenadiary.com

関連

light11.hatenadiary.com

light11.hatenadiary.com

light11.hatenadiary.com

参考

docs.unity3d.com