Addressable基礎編シリーズ(8~9)

この記事は2つのセクションに分けられます。最初の部分において、この前にリリースしたAddressable基礎編シリーズ文章を簡単にまとめます。そして、リリースしていない第八と九の節を紹介します。


この前に公開したブログのタイトルと内容は以下のように示しています。

Assetsについて――Unityアセットマッピング

内容:Assetsとは何か、Assetsの識別と参照、Assetsのライフサイクル

Resourcesディレクトリのメリットと問題点

内容:特別なプロジェクトディレクトリ、Resourcesの詳説、

AssetBundleの原則

内容:AssetBundleの仕組み、AssetBundleのローディング、AssetBundleからのアセットローディング

AssetBundleのベストプラクティス

内容:ロードされたAssetsの管理、AssetBundleのリリース、Assetsの構成策、AssetBundleバリアント、AssetBundle圧縮、Crunch圧縮、

Addressable Assets Systemの概要

内容:Addressableのインストール、Addressable Assetsの用意、Addressable Assetsの使用法、ビルド、Addressableシステムのアップグレード

Addressable Assets開発サイクル

Addressable Assets管理、ビルドスクリプト、デバッグ、更新ワークフロー

Addressable Assetのホストサービス

Packed Modのテストと反復、設定、カスタムサービス


八、Addressable Assetsメモリ管理

8.1 ミラーリングロードとアンロード

Addressable Assets を使用する場合、適切なメモリ管理を確保するための主な方法は、ロードとアンロードの呼び出しを適切に管理することです。 やり方はアセットの種類や読み込み方法によって異なります。 ただし、すべての場合において、リリース メソッドは、読み込まれたアセットまたは Load によって返された操作ハンドルのいずれかを受け入れることができます。 たとえば、シーンの作成中 (以下で説明)、Load は AsyncOperationHandle を返し、この返されたハンドルを介して、またはハンドルを保持することによって、AsyncOperationHandle を同期的に解放します。

 

8.1.1 アセットのロード

アセットを読み込むには、Addressables.LoadAssetAsync または Addressables.LoadAssetsAsync を使用します。

 

これにより、アセットをインスタンス化せずにメモリにロードします。 ロード呼び出しが実行されるたびに、ロードされた各アセットに参照カウントが追加されます。 LoadAssetAsync を同じアドレスで 3 回呼び出すと、AsyncOperationHandle 構造体の 3 つの異なるインスタンスが作成され、すべて同じ基になる操作が参照されます。 この操作には、対応するアセットの参照カウントが 3 あります。 ロードが成功すると、結果の AsyncOperationHandle 構造の .Result プロパティにアセットが含まれます。 Unity の組み込みのインスタンス化メソッドを使用して、読み込まれたアセットでインスタンス化できます。これにより、Addressable の参照カウントが増加しません。

 

アセットをアンロードするには、Addressables.Releases メソッドを使用します。これにより、ref カウントが減少します。 特定の Asset の参照カウントがゼロになると、その Asset はアンロードされ、依存関係の参照カウントが減少します。

 

注: アセットは、既存の依存関係に応じて、すぐにアンロードされる場合とされない場合があります。

 

8.1.2 シーンのロード

シーンを読み込むには、Addressables.LoadSceneAsync を使用します。 このメソッドを使用して、開いているすべてのシーンを閉じるシングル モードでシーンをロードするか、追加モードでシーンをロードできます。詳細については、シーン モードのロードに関するドキュメントを参照してください。

シーンをアンロードするには、Addressables.UnloadSceneAsync を使用するか、シングル モードで新しいシーンを開きます。 Addressables インターフェイスを使用するか、SceneManager.LoadScene または SceneManager.LoadSceneAsync メソッドを使用して、新しいシーンを開くことができます。 新しいシーンを開くと、現在のシーンが閉じられ、参照カウントが適切に減少します。

 

8.1.3 ゲームオブジェクトのインスタンス化

GameObject アセットをロードしてインスタンス化するには、Addressables.InstantiateAsync を使用します。 これにより、指定されたアドレス パラメータによって配置されたプレハブがインスタンス化されます。 Addressable システムはプレハブとその依存関係を読み込み、関連するすべてのアセットの参照カウントを増やします。

 

同じアドレスで InstantiateAsync を 3 回呼び出すと、関連するすべてのアセットの参照カウントが 3 になります。 ただし、LoadAssetAsync を 3 回呼び出す代わりに、各 InstantiateAsync 呼び出しは、一意の操作を指す AsyncOperationHandle を返します。 これは、各 InstantiateAsync の結果が一意のインスタンスであるためです。 InstantiateAsync とその他の Load 呼び出しのもう 1 つの違いは、オプションの trackHandle パラメーターです。 false に設定すると、使用する AsyncOperationHandle をインスタンスの解放時に保持する必要があります。 これはより効率的ですが、より多くの開発作業が必要になります。

 

インスタンス化されたゲームオブジェクトを破棄するには、Addressables.ReleaseInstance を使用するか、インスタンス化されたオブジェクトを含むシーンを閉じます。 このシーンは Additive モードまたは Single モードでロード (およびクローズ) できます。 このシーンは、Addressable または SceneManagementAPI を使用してロードすることもできます。 前述のように、trackHandle を false に設定すると、Addressables.ReleaseInstance を実際の GameObject ではなく、ハンドルでのみ呼び出すことができます。

 

注: Addressables API を使用して作成されていないインスタンス、または trackHandle==false で作成されたインスタンスで Addressables.ReleaseInstance が呼び出された場合、システムはこれを検出し、メソッドが指定されたインスタンスを解放できなかったことを示す false を返します。 この場合、インスタンスは破棄されません。

 

InstantiateAsync には関連するオーバーヘッドがあるため、フレームごとに同じオブジェクトを何百回もインスタンス化する必要がある場合は、Addressables API を介して読み込み、次に他のメソッドを介してインスタンス化することを検討してください。 この場合、Addressables.LoadAssetAsync を呼び出してから結果を保存し、その結果に対して GameObject.Instantiate() を呼び出すことができます。 これにより、インスタンス化を同期的に呼び出す柔軟性が得られます。 欠点は、Addressable システムが作成したインスタンスの数を認識できないことです。これは、適切に管理されていないとメモリの問題を引き起こす可能性があります。 たとえば、テクスチャを参照するプレハブには、参照する有効な読み込まれたテクスチャがなくなり、バグ (またはクラッシュ) が発生します。 これらの問題は、メモリ GC をすぐにトリガーしない可能性があるため、追跡するのが困難です (メモリのクリアに関する以下のセクションを参照してください)。

 

8.1.4 データのロード

データの読み込みでは、AsyncOperationHandle.Result が発行するインターフェイスは必要ありませんが、操作自体を解放する必要があります。 たとえば、Addressables.LoadResourceLocationsAsync と Addressables.GetDownloadSizeAsync です。 リリース操作までアクセスできるデータをロードします。 このリリースは、Addressables.Releases で実行できます。

 

8.1.5 バックグラウンドでのやり取り

AsyncOperationHandle.Result フィールドに何も返さない操作には、完了時に操作ハンドルを自動的に解放するオプションのパラメーターがあります。 これらのアクション ハンドルの完了後にいずれかのアクション ハンドルが不要になった場合は、autoReleaseHandle パラメーターを true に設定して、アクション ハンドルが確実にクリアされるようにします。 autoReleaseHandle を false にするシナリオは、完了後にアクション ハンドルのステータスを確認する必要がある場合です。 これらのインターフェイスの例は、Addressables.DownloadDependenciesAsync と Addressables.UnloadScene です。

 

8.2 Addressables イベント ビューア

Addressables Event Viewer ウィンドウを使用して、すべての Addressable システム操作の参照カウントを監視します。 エディターでウィンドウにアクセスするには、[ウィンドウ] > [AssetManagement] > [Addressables] > [Event Viewer] を選択します。

 

注: イベント ビューアーでデータを表示するには、AddressableAssetSettings オブジェクトのインスペクターで SendProfilerEvents 設定を有効にする必要があります。

 

イベント ビューアには次の情報があります。

  • 白い縦線は、ロード要求が発生したフレームを示します。
  • 青色の背景は、現在読み込まれているアセットを示します。
  • グラフの緑色の部分は、アセットの現在の参照カウントを表します。

8.3 メモリクリア時

参照されなくなったアセット (Analyzer の青色のセクションの終わりで示される) は、必ずしもアセットがアンロードされたことを意味するわけではありません。 一般的に適用されるシナリオには、AssetBundle 内の複数のアセットが含まれます。

例えば:

  1. 1 つの AssetBundle に 3 つのアセット (木、タンク、牛) があります。
  2. ツリーがロードされると、プロファイラーはツリーの参照カウントを表示し、AssetBundle は参照カウントを表示します。
  3. タンクがロードされると、プロファイラーはツリーとタンクのそれぞれに対して 1 つの参照カウントを表示しますが、AssetBundle に対しては 2 つの参照カウントを表示します。
  4. ツリーを解放すると、参照番号がゼロになり、青いバーが消えます。

 

この例では、ツリー アセットはこの時点では実際にはアンロードされていません。 AssetBundle またはその一部をロードできますが、AssetBundle を部分的にアンロードすることはできません。 バンドル内のアセットは、アセットバンドル自体が完全にアンロードされるまでアンロードされません。 このルールの例外は、エンジン インターフェイス Resources.UnusedAsset の呼び出しです。 上記のシナリオでこのメソッドを実行すると、ツリーがアンロードされます。 Addressables システムはこれらのイベントを認識する方法がないため、プロファイラー グラフには Addressable の参照カウントのみが反映されます (メモリ容量は反映されません)。 Resources.UnusedAsset の使用を選択した場合、これは非常に遅い操作であり、通常の表示に影響を与えない画面 (読み込み画面など) でのみ呼び出す必要があることに注意してください。

 

8.4 非同期操作ハンドル

Addressables API のいくつかのメソッドは、AsyncOperationHandle 構造を返します。 このハンドルの主な目的は、操作のステータスと結果にアクセスできるようにすることです。 操作の結果は、Addressables.Relace または Addressables.ReleaseInstance が呼び出されるまで有効です。

 

操作が完了すると、AsyncOperationHandle.Status プロパティは AsyncOperationStatus.Succeeded または AsyncOperationStatus.Failed になります。 成功した場合、AsyncOperationHandle.Result プロパティを介して結果にアクセスできます。

 

操作のステータスを定期的に確認したり、AsyncOperationHandle.Complete イベントを使用して完了したコールバックを登録したりできます。 返された AsyncOperationHandle 構造体によって提供されるアセットが不要になった場合は、Addressables.Releases メソッドを使用して解放する必要があります。

 

8.4.1 Type および .typeless ハンドル

ほとんどの Addressables API メソッドは、AsyncOperationHandle.Completed イベントと AsyncOperationHandle.Result オブジェクトのタイプ セーフを保証する汎用 AsyncOperationHandle 構造体を返します。 非ジェネリックの AsyncOperationHandle 構造もあり、必要に応じてこれら 2 つのハンドルを変換できます。

 

非ジェネリック ハンドルを不適切な型のジェネリック ハンドルにキャストしようとすると、実行時例外が発生することに注意してください。 例えば:

8.4.2 AsyncOperationHandleの使用例

AsyncOperationHandle.Completed コールバックを使用して、完了イベントのリスナーを登録します。

AsyncOperationHandle は IEnumerator を実装するため、コルーチンで生成できます。

Addressable は、AsyncOperationHandle.Task プロパティを介して非同期 await もサポートします。

AsyncOperationHandle.Task プロパティは WebGL では使用できません。WebGL ではマルチスレッド操作がサポートされていないためです。 allowSceneActivation を false に設定して SceneManager.LoadSceneAsync を使用するか、または activateOnLoad パラメーターを false に設定して Addressables.LoadSceneAsync を使用してシーンをロードすると、後続の非同期操作でロードの完了がブロックされる可能性があることに注意してください。 lowSceneActivation のドキュメントを参照してください。

8.5 カスタム操作の作成

IResourceProvider API を使用すると、データ駆動型の方法で場所と依存関係を定義することにより、読み込みプロセスを拡張できます。 場合によっては、カスタム アクションを作成したいことがあります。 IResourceProviderAPI は、これらのカスタム操作の上に内部的に構築されます。

 

カスタム操作を実装するには、AsyncOperationBase クラスから派生させ、必要な仮想メソッドをオーバーライドすることにより、カスタム操作を作成できます。 派生操作を ResourceManager.StartOperation メソッドに渡して操作を開始し、AsyncOperationHandle 構造を受け取ることができます。 この方法で開始されたアクションは ResourceManager に登録され、Addressables Event Viewer に表示されます。

 

  • operationResourceManager を実行すると、カスタム操作のために AsyncO が呼び出されますoperationBase. メソッドの実行。
  • 完了処理 カスタム操作が完了したら、カスタム操作オブジェクト AsyncOperationBase.Complete を呼び出します。 これは Execute メソッドで呼び出すことも、呼び出しの外に置くこともできます。 AsyncOperationBase.Complete を呼び出すと、操作が完了したことが ResourceManager に通知され、関連する AsyncOperationHandle.Completed イベントが呼び出されます。
  • 操作の終了 AsyncOperationHandle を参照する AsyncOperationHandle を発行すると、ResourceManager はカスタム操作の AsyncOperationBase.Destroy メソッドを呼び出します。 ここで、カスタム アクションに関連付けられたメモリまたはリソースを解放する必要があります。

 


九、Addressablesアナライザー

Analyze は、プロジェクト アドレスのレイアウトに関する情報を収集するためのツールです。 場合によっては、アナライザーが適切なアクションを実行してアイテムの状態をクリーンアップすることがあります。 それ以外の場合、プロファイリングは、Addressable レイアウトについてより多くの情報に基づいた決定を下せるようにする純粋な情報ツールです。

9.1 Analyzeの使用

エディターで、Addressables Analyze ウィンドウを開く ([Window] > [Asset Management] > [Addressables] > [Analyze]) か、[Addressables Groups] ウィンドウから [Tools] > [Analyze] ボタンをクリックして開きます。

 

[Analyze] ウィンドウには、分析ルールのリストと次の操作が表示されます。

 

  • Analyze Selected Rules(選択したルールを分析)
  • Clear Selected Rules(選択したルールをクリア)
  • Fix Selected Rules(選択したルールを修正)

 

9.1.1 Analyze Operation

Analyze Operationは、ルールの情報収集ステップです。 これをルールまたはルールセットで実行すると、ビルド、依存関係マップなどに関するデータが収集されます。 各ルールは、必要なデータを収集し、それを AnalyzeResult オブジェクトのリストとして報告する役割を果たします。

 

分析ステップ中は、データまたはプロジェクトの状態を変更するアクションを実行しないでください。 このステップで収集されたデータに基づいて、是正措置が適切な一連の措置である可能性があります。 ただし、一部のルールには分析ステップが 1 つしか含まれていません。これは、収集された情報に基づいて合理的、適切、かつ通常のアクションを実行できないためです。  Check Scene to Addressable Duplicate DependenciesとCheck Resources to Addressable Duplicate Dependenciesは、そのようなルールの例です (以下)。

 

純粋に情報提供のみを目的とし、修正アクションを含まないルールはUnfixable Rulesとして分類され、固定アクションを含むルールはFixable Rulesとして分類されます。

 

9.1.2 Clear step

このアクションは、分析によって収集されたすべてのデータを削除し、それに応じて TreeView を更新します。

 

9.1.3 Fix operation

修正可能なルールの場合、修正操作の実行を選択できます。 これは、分析ステップ中に収集されたデータを使用して、必要な変更を行い、問題を解決します。

 

分析で検出された問題を修正するために合理的で適切なアクションを実行できるため、Check Duplicate Bundle DependenciesはFixable Ruleの例の一つです。

 

9.2 提供されている分析ルール

9.2.1 修復可能なルール

 

9.2.1.1 重複するバンドル依存関係のチェック

このルールは、BundledAssetGroupSchemas を使用するすべてのグループをスキャンし、アセット グループのレイアウトを投影することによって、潜在的に冗長なアセットをチェックします。 これは実際には完全なビルドをトリガーするため、このチェックには非常に時間とパフォーマンスがかかります。

 

問題: 冗長なアセットは、異なるグループのアセットが依存関係を共有しているためです。 たとえば、2 つのプレハブが、異なるアドレス可能グループに存在するマテリアルを共有します。 これらのマテリアル (およびその依存関係) は、それぞれがプレハブを持つ 2 つのグループに分けられます。 これが起こらないようにするには、プレハブの 1 つまたは独自のスペースでマテリアルをアドレス指定可能としてマークし、マテリアルとその依存関係を単一のアドレス指定可能グループにグループ化する必要があります。

 

解決策: このチェックで問題が見つかった場合、このルールに対して FIX 操作を実行すると、新しい Addressable Group が作成され、すべての依存アセットが移動されます。

 

例外: 複数のオブジェクトを含むアセットがある場合、異なるグループは、コピーを作成する代わりに、アセットの一部のみを抽出できます。 多くのメッシュを含む FBX がその例です。 1 つのメッシュが「GroupA」にあり、別のメッシュが「GroupB」にある場合、このルールは FBX が共有されていると見なし、修復操作の実行時にそれを別のグループにアンパックします。 この場合、どちらのグループにも完全な FBX アセットがないため、FIX 操作の実行は実際には有害です。

 

また、冗長なアセットが常に問題になるわけではないことに注意してください。 アセットが同じユーザー グループ (地域固有のアセットなど) によって要求されない場合、冗長な依存関係が必要になるか、少なくとも冗長性は無関係です。 各アイテムはユニークでユニークです。 したがって、冗長なアセットの依存関係の修正は、ケースバイケースで評価する必要があります。

 

9.2.2 修復不可能なルール

 

9.2.2.1 アドレス可能な重複依存関係に対するリソースのチェック

このルールは、構築された Addressable データと Resources フォルダーに存在するアセットとの間にアセットまたはアセット依存関係の冗長性があるかどうかを検出します。

 

問題: これらの冗長性は、データがアプリ ビルドと Addressable ビルドの両方に含まれることを意味します。

 

解決策: 適切なアクションが存在しないため、このルールは修正できません。 これは単なる情報提供であり、冗長性を警告します。 分析された場合は、手動で解決する必要があります。 考えられる手動修正の例は、問題のあるアセットを Resources フォルダーから移動し、それを Addressable にすることです。

 

9.2.2.2 Check Scene to Addressable Duplicate Dependencies

このルールは、エディターのシーン リスト内のシーンと Addressable 内のシーンの間で共有されるアセットまたはアセットの依存関係を検出します。

 

問題: これらの冗長性は、データがアプリ ビルドと Addressable ビルドの両方に含まれることを意味します。

 

解決策: これは単なる情報提供であり、冗長性を警告しています。 分析された場合は、手動で解決する必要があります。 可能な手動修正の例は、参照が重複しているビルトイン シーンを BuildSettings から引き出し、それを Addressable シーンにすることです。

 

9.2.2.3 Check Sprite Atlas to Addressable Duplicate Dependencies

Addressable sprite atlasを指定すると、このルールは、アトラス内のスプライトが他の場所で Addressable としてマークされているかどうかを検出します。

 

問題: これらの冗長性は、スプライト データが Addressable ビルドの複数の領域で複製されることを意味します。

解決策: これは単なる情報提供であり、冗長性を警告しています。 分析された場合は、手動で解決する必要があります。 可能な手動修正の例は、アドレス可能から重複したスプライトを削除し、アセットがスプライトを直接参照するのではなく、アドレス可能スプライト アトラス内のスプライトを参照するようにすることです。

 

9.2.2.4 ビルド バンドル レイアウト

このルールは、Addressable ビルドで Assets を Addressable として明示的にマークする方法を示します。 これらの明示的なアセットについては、ビルドによって暗黙的に参照され、最終的にビルドに取り込まれるアセットも示します。

 

このルールの下で収集されたデータは、特定の問題を示すものではありません。 これは純粋な情報です。

 

9.3 Analyze拡張子

固有のプロジェクトごとに、事前にパッケージ化されたものだけでなく、追加の分析ルールが必要になる場合があります。 Addressable Assets System を使用すると、独自のカスタム ルール クラスを作成できます。

 

9.3.1 AnalyzeRule オブジェクト

AnalyzeRule クラスのサブクラスを作成し、次のプロパティをオーバーライドします。

 

CanFix: 分析ルールが修正可能と見なされるかどうかを示します。

ruleName 分析ウィンドウにルールを表示するために使用される名前。

 

次のように、次のメソッドをオーバーライドする必要もあります。

List RefreshAnalysis(AddressableAssetSettings settings)

void FixIssues(AddressableAssetSettings settings)

void ClearAnalysis()

注: ルールが修正不可能として指定されている場合、FixIssues メソッドをオーバーライドする必要はありません。

9.3.1.1 RefreshAnalysis

これが分析操作です。 この方法では、必要な計算を実行し、修復に必要なデータをキャッシュします。 戻り値はリストリストです。データを収集した後、分析のエントリごとに新しい AnalyzeResult を作成し、データを文字列として最初の引数として、MessageType を 2 番目の引数として使用します (オプションで、メッセージの種類を警告またはエラーとして指定します)。 作成されたオブジェクトのリストを返します。

 

特定の AnalyzeResult オブジェクトの TreeView に子要素を作成する必要がある場合は、kDelimiter を使用して親要素と子要素を記述することができます。 親と子の間に区切りを含めます。

 

9.3.1.2 FixIssues

これはあなたの修正です。 分析ステップに応じて適切なアクションを実行する必要がある場合は、ここで実行します。

 

9.3.1.3 ClearAnalysis

これがクリーンアップ操作です。 分析ステップ中にキャッシュされたデータは、この関数でクリアまたは削除できます。 TreeView は同時に更新され、必要なデータが不足していることを示します。

 

9.3.2 カスタム ルールを GUI に追加する

分析ウィンドウに表示するには、AnalyzeWindow.RegisterNewRule() を使用してカスタム ルールを GUI クラスに登録する必要があります。


Addressable基礎編シリーズは以上です。

投稿ありがとうございます。

投稿者の情報は以下です。

牛飼の星(放牛的星星)

U Sparkle開発者企画参加者

Zhihu HP:https://www.zhihu.com/people/niuxingxing


UWA公式サイト:https://jp.uwa4d.com
UWA公式ブログ:https://blog.jp.uwa4d.com
UWA公式Q&Aコミュニティ(中国語注意):https://answer.uwa4d.com