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

作成: 2026-02-05最終更新: 2026-07-13

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

「ビルドサイズが大きすぎる…」「メモリ管理が複雑で大変…」「ダウンロードコンテンツを配信したい…」——アセットが増えてきたプロジェクトの悩みは、だいたいこの3つに行き着きます。

Addressables(アドレサブル) は、Unity公式のアセット管理システムです。AssetBundleをベースにしながら、依存関係の管理、メモリ管理、ロード元の切り替えを自動化します。この記事では、導入からロード・アンロードの書き方、メモリリークの検出、実際のボス戦への組み込みまでを解説します。

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

Addressablesのイメージ。粘土の配送センターで、アドレスラベルの付いた小包がコンベアで運ばれ、ロボットがゲームアセット(剣・キャラ・音符)を取り出している

この記事でわかること

  • AssetBundleとの違い——Addressablesは面倒ごとの自動化レイヤー
  • Addressable化の2つの方法(Inspector/AssetReference
  • ロードの書き分け(コールバック・async/await・ラベル・InstantiateAsync)
  • アンロードとメモリリーク検出(Release・Event Viewer)
  • Play Modeの使い分けとベストプラクティス

前提: 「そもそもなぜ直接参照やResourcesではダメなのか」というアセット管理の考え方は Resources卒業ガイド で解説しています。

Sponsored

AssetBundleとの違い

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

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

Addressablesの概念図。アドレスで注文すると、Addressablesがローカルまたはサーバーの置き場所から探して届けてくれる

インストール方法

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;
}
Sponsored

アセットのロード方法

ロードの書き方は複数あります。まず全体像から——基本は「型安全なAssetReference」、まとめてロードは「ラベル」、と覚えてから各方法を見ていくと迷いません。

Addressablesのロード方法4種の使い分け。アドレス文字列は手軽だがタイプミス注意、AssetReferenceは型安全でおすすめ、InstantiateAsyncはロードと生成を同時に、ラベルはステージ単位でまとめて

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

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

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

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

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

    void OnDestroy()
    {
        // 借りたハンドルは必ず返す(返し忘れ=メモリリーク)
        if (handle.IsValid())
            Addressables.Release(handle);
    }
}

重要: LoadAssetAsyncで借りたPrefabからInstantiateした場合、そのインスタンスの中身(メッシュやテクスチャ)は ハンドルが支えています。インスタンスがまだ生きているのにReleaseすると、動いている敵から実体が抜かれて表示が壊れる危険があります。 解放は「インスタンスをすべて破棄した後」 が鉄則です。生成と解放を1対1で自動管理したい場合は、後述のInstantiateAsyncReleaseInstanceのペアが安全です。

方法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でロードしたアセットは、必ずアンロードする必要があります。アンロードしないと、メモリリークが発生します。

内部では参照カウントが動いています。ロードで+1、解放で-1、0になった瞬間にメモリから降ろせる——「図書館の貸出カード」のような仕組みです。

参照カウントの図。Loadで+1されカウントが増え、Releaseで-1され、0になったアセットは解放される
// アドレス文字列でロードした場合
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を使用本番環境に近い動作確認
Play Modeの3段階。Use Asset Database=開発中の高速イテレーション、Simulate Groups=依存関係やメモリの確認、Use Existing Build=本番に近い最終確認、と開発から本番へ段階的に切り替える
Sponsored

実践:ボス戦の直前ロードを組む

アクションRPGの重量級ボス、レイドの巨大モンスター、紙芝居ゲームの高解像度イベントCG——「普段は要らないが、その瞬間だけ確実に必要」なアセットこそ、Addressablesの主戦場です。定番の「ボス部屋の扉」を組んでみましょう。

ボス戦直前ロードの流れ。扉の前でロードを開始し、ロード済みのボスと戦闘し、撃破後にReleaseで解放する。使う直前に借りて使い終わったら返す

流れは「扉の前でロード開始 → 開扉時には準備完了 → 撃破後に解放」です。

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

public class BossGate : MonoBehaviour
{
    [SerializeField] private AssetReference bossPrefab;   // ボスのAddressableプレハブ
    [SerializeField] private Transform bossSpawnPoint;

    private AsyncOperationHandle<GameObject> handle;
    private GameObject bossInstance;

    // プレイヤーが扉のエリアに入ったら、先にロードを始めておく
    private void OnTriggerEnter(Collider other)
    {
        if (!other.CompareTag("Player")) return;
        if (handle.IsValid()) return;                       // 出入りの再入で二重ロードしない
        handle = bossPrefab.LoadAssetAsync<GameObject>();   // 裏でロード開始
    }

    // 扉が開くタイミングで呼ぶ(ロードが終わっていなければ待つ)
    public async void OpenGate()
    {
        GameObject prefab = await handle.Task;              // 大抵はもう完了している
        bossInstance = Instantiate(prefab, bossSpawnPoint.position, Quaternion.identity);
    }

    // ボス撃破時に呼ぶ
    public void OnBossDefeated()
    {
        Destroy(bossInstance);          // 先にインスタンスを破棄してから——
        Addressables.Release(handle);   // ——参照カウントを返す(この順番が大事)
    }
}

ポイントは2つです。

  • 「入口で借りて、出口で返す」を対にする: OnTriggerEnterでロードを始めたら、OnBossDefeated(またはこのオブジェクトのOnDestroy)で必ずRelease借りと返しをコードの近い場所にペアで書くのがリーク防止のいちばんの習慣です。返すのは 必ずインスタンスを破棄した後——生きているボスの足元からアセットを抜かないこと。
  • ロードは「気づかれないうちに」始める: ボス部屋の少し手前の通路など、演出的に自然な場所でロードを始めれば、プレイヤーはロード時間を感じません。「ムービーの裏」「エレベーターの中」も同じ発想の定番です。

なお、シーンごと動的ロードしたい場合は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を自動的にロード
  • 参照カウントでメモリ管理 - 「借りたらReleaseで返す」を守れば、解放タイミングをシステムが正確に管理してくれる
  • ダウンロードコンテンツを簡単に配信できる - リモートサーバーからのダウンロードに対応

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

さらに学ぶために