【Unity】Unity Addressables入門:アセット管理とメモリ効率を劇的に改善する

作成: 2026-02-05

Unity公式のアセット管理システムAddressablesの使い方を解説。AssetBundleの複雑な管理を自動化し、ビルドサイズ削減やダウンロードコンテンツ配信を簡単に実現できます。

概要

動作確認環境: Unity 2022.3 LTS / Unity 6

「ビルドサイズが大きすぎる…」「メモリ管理が複雑で大変…」「ダウンロードコンテンツを配信したい…」

Unity開発をしていると、アセット管理の問題に直面することがあります。Addressables(アドレサブル) は、Unity公式のアセット管理システムです。AssetBundleをベースにしながら、依存関係の管理、メモリ管理、ロード元の切り替えを自動化します。これにより、複雑なアセット管理をシンプルに実現できます。

AssetBundleとの違い

AssetBundle は、アセットを圧縮してビルドサイズを削減したり、ダウンロードコンテンツを配信したりするための低レベルな仕組みです。しかし、AssetBundleを実際に使うには、依存関係の管理、メモリ管理、ロード元の切り替えなど、多くの実装が必要でした。

Addressablesは、内部的にはAssetBundleを使用していますが、これらの複雑な管理を自動化します。開発者は、アセットに「アドレス」を付けて、そのアドレスでロードするだけです。

インストール方法

Addressablesは、Package Managerからインストールできます。

  1. Unityエディタのメニューから「Window」→「Package Manager」を選択
  2. 左上のドロップダウンメニューから「Unity Registry」を選択
  3. リストから「Addressables」を探してクリック
  4. 右下の「Install」ボタンをクリック

インストールが完了すると、アセットのインスペクターに「Addressable」チェックボックスが表示されるようになります。

アセットをAddressable化する

方法1:インスペクターでAddressableにする

最も簡単な方法は、アセットのインスペクターで「Addressable」チェックボックスをオンにすることです。

  1. Projectウィンドウでアセットを選択
  2. インスペクターで「Addressable」チェックボックスをオン
  3. アドレス名を設定(デフォルトはアセットのパス)

方法2:AssetReferenceフィールドに割り当てる

MonoBehaviourやScriptableObjectにAssetReferenceフィールドを追加し、インスペクターでアセットを割り当てることでも、Addressable化できます。

using UnityEngine;
using UnityEngine.AddressableAssets;

public class Example : MonoBehaviour
{
    public AssetReference assetReference;
}

アセットのロード方法

方法1:アドレス文字列でロード(Completedコールバック)

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class LoadByAddress : MonoBehaviour
{
    void Start()
    {
        Addressables.LoadAssetAsync<GameObject>("Enemy").Completed += OnLoadCompleted;
    }

    void OnLoadCompleted(AsyncOperationHandle<GameObject> handle)
    {
        if (handle.Status == AsyncOperationStatus.Succeeded)
        {
            GameObject prefab = handle.Result;
            Instantiate(prefab);
        }
        else
        {
            Debug.LogError($"Failed to load asset: {handle.OperationException}");
        }
    }
}

方法1.5:async/awaitでロード(推奨)

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class LoadByAddressAsync : MonoBehaviour
{
    private AsyncOperationHandle<GameObject> handle;

    async void Start()
    {
        try
        {
            handle = Addressables.LoadAssetAsync<GameObject>("Enemy");
            GameObject prefab = await handle.Task;
            Instantiate(prefab);
        }
        catch (System.Exception e)
        {
            Debug.LogError($"Failed to load asset: {e.Message}");
        }
    }

    void OnDestroy()
    {
        if (handle.IsValid())
            Addressables.Release(handle);
    }
}

async/awaitのメリット: コールバック地獄を避けられ、try-catchでエラーハンドリングが直感的に書けます。

注意: async voidはfire-and-forget(発火して忘れる)パターンとなり、例外が呼び出し元に伝播しません。本格的なプロジェクトではUniTaskUnity 6のAwaitable の使用を検討してください。

方法2:AssetReferenceでロード

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class LoadByReference : MonoBehaviour
{
    public AssetReference assetReference;

    void Start()
    {
        assetReference.LoadAssetAsync<GameObject>().Completed += OnLoadCompleted;
    }

    void OnLoadCompleted(AsyncOperationHandle<GameObject> handle)
    {
        if (handle.Status == AsyncOperationStatus.Succeeded)
        {
            GameObject prefab = handle.Result;
            Instantiate(prefab);
        }
    }

    void OnDestroy()
    {
        assetReference.ReleaseAsset();
    }
}

方法2.5:InstantiateAsyncでロードと生成を同時に

InstantiateAsyncを使うと、ロードとインスタンス化を1ステップで行えます。

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class InstantiateExample : MonoBehaviour
{
    public AssetReference assetReference;
    private AsyncOperationHandle<GameObject> handle;
    private GameObject spawnedObject;

    void Start()
    {
        handle = assetReference.InstantiateAsync(transform.position, Quaternion.identity);
        handle.Completed += OnInstantiateCompleted;
    }

    void OnInstantiateCompleted(AsyncOperationHandle<GameObject> op)
    {
        if (op.Status == AsyncOperationStatus.Succeeded)
        {
            spawnedObject = op.Result;
            Debug.Log($"Instantiated: {spawnedObject.name}");
        }
    }

    void OnDestroy()
    {
        // InstantiateAsyncで生成したオブジェクトはReleaseInstanceでアンロード
        // これにより生成されたGameObjectも破棄される
        if (handle.IsValid())
            Addressables.ReleaseInstance(handle);
    }
}

ライフサイクルの注意: ReleaseInstanceを呼ぶと、生成されたGameObjectも自動的に破棄されます。オブジェクトを手動でDestroyした場合でも、ReleaseInstanceでハンドルを解放してください。

方法3:ラベルでロード

複数のアセットに同じラベルを付けて、そのラベルで一度にロードすることもできます。

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using System.Collections.Generic;

public class LoadByLabel : MonoBehaviour
{
    private List<GameObject> loadedPrefabs = new List<GameObject>();
    private AsyncOperationHandle<IList<GameObject>> handle;

    void Start()
    {
        handle = Addressables.LoadAssetsAsync<GameObject>(
            "enemies",
            prefab => {
                // 各アセットがロードされるたびに呼ばれる
                loadedPrefabs.Add(prefab);
                Debug.Log($"Loaded: {prefab.name}");
            }
        );
        handle.Completed += OnAllLoaded;
    }

    void OnAllLoaded(AsyncOperationHandle<IList<GameObject>> op)
    {
        if (op.Status == AsyncOperationStatus.Succeeded)
        {
            Debug.Log($"All {op.Result.Count} assets loaded.");
        }
    }

    void OnDestroy()
    {
        Addressables.Release(handle);
    }
}

ラベルの命名規則: ラベル名は小文字のケバブケースまたはスネークケースを推奨します(例:stage-1-assetsenemy_prefabs)。大文字やスペースは避けてください。

アセットのアンロード

Addressablesでロードしたアセットは、必ずアンロードする必要があります。アンロードしないと、メモリリークが発生します。

// アドレス文字列でロードした場合
Addressables.Release(handle);

// AssetReferenceでロードした場合
assetReference.ReleaseAsset();

Play Modeの使い分け

Addressablesには、3つのPlay Modeがあります。

Play Mode説明用途
Use Asset Database (fastest)AssetDatabaseから直接ロード開発中の高速イテレーション
Simulate Groups (advanced)AssetBundleをシミュレート依存関係やメモリ管理の確認
Use Existing Build実際のAssetBundleを使用本番環境に近い動作確認

実践的な使用例

例1:プレハブを動的にロードしてインスタンス化

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class SpawnEnemy : MonoBehaviour
{
    public AssetReference enemyPrefab;
    private AsyncOperationHandle<GameObject> handle;

    void Start()
    {
        handle = enemyPrefab.LoadAssetAsync<GameObject>();
        handle.Completed += OnLoadCompleted;
    }

    void OnLoadCompleted(AsyncOperationHandle<GameObject> op)
    {
        if (op.Status == AsyncOperationStatus.Succeeded)
        {
            Instantiate(op.Result, transform.position, Quaternion.identity);
        }
    }

    void OnDestroy()
    {
        enemyPrefab.ReleaseAsset();
    }
}

例2:シーンを動的にロード

public AssetReference sceneReference;

public void LoadSceneAdditive()
{
    sceneReference.LoadSceneAsync(LoadSceneMode.Additive);
}

メモリリークの検出:Event Viewer

Addressablesでは「必ずアンロードする」ことが重要ですが、本当にアンロードできているか確認する方法が必要です。

Addressables Event Viewer を使うと、ロード中のアセットをリアルタイムで確認できます。

Event Viewerの開き方

  1. Window > Asset Management > Addressables > Event Viewerを選択
  2. Play Modeでゲームを実行
  3. ロード/アンロードの状況がリアルタイムで表示される

確認ポイント

  • シーン遷移後にアセットが残っていないか
  • 同じアセットが複数回ロードされていないか
  • 参照カウントが正しく減少しているか

注意: Event Viewerを使用するには、Addressables設定で「Send Profiler Events」を有効にする必要があります。

ベストプラクティス

  • アセットをグループ化する - 関連するアセットは同じグループにまとめる
  • ラベルを活用する - 複数のアセットを一度にロードしたい場合に便利
  • AssetReferenceを使う - 型安全で、インスペクターでアセットを直接割り当てられる
  • 必ずアンロードする - OnDestroyOnDisableでアンロードする
  • Play Modeを使い分ける - 開発中はUse Asset Database、最終確認時はUse Existing Build
  • Event Viewerで検証する - メモリリークがないか定期的に確認

まとめ

Addressablesは、Unity公式のアセット管理システムです。AssetBundleをベースにしながら、依存関係の管理、メモリ管理、ロード元の切り替えを自動化します。

  • ロード元を簡単に切り替えられる - 設定変更だけで開発用とリリース用を切り替え
  • 依存関係を自動的に解決する - 依存するAssetBundleを自動的にロード
  • メモリ管理を自動化する - 参照カウンタによる自動メモリ管理
  • ダウンロードコンテンツを簡単に配信できる - リモートサーバーからのダウンロードに対応

ぜひ、Addressablesを活用して、効率的なアセット管理を実現してください。

さらに学ぶために