Unity Term Book
Advanced Techniques

Addressables

Addressables is an advanced asset system — load assets asynchronously by address (key), with DLC, CDN streaming, and automatic memory management at runtime.

Imagine...

Resources.Load() is walking into a warehouse yourself — you need the exact path and you wait. Addressables is Amazon delivery: you name the item (address), the service finds it locally or downloads it from a CDN. You get a handle like a tracking number — the game is not blocked; a callback fires when it arrives. Releasing the handle is the service reclaiming memory.

The concept in detail

The Addressable Asset System fixes Resources folder limits (cannot unload one asset, hardcoded paths, no CDN) and raw AssetBundles (complex API, manual dependency tracking). Addressables sits on AssetBundles but automates most of the work.

Each asset is marked Addressable and given an Address (a string key, e.g. “prefabs/hero_sword”). Assets go into Groups — each group compiles to one AssetBundle. A group can be Local (in the build) or Remote (uploaded to a CDN). Labels let you load many assets at once by tag.

Main API: Addressables.LoadAssetAsync<T>(key) returns AsyncOperationHandle<T> — await it, or subscribe to .Completed. Important: call Addressables.Release(handle) when you are done — otherwise the asset never unloads (memory leak).

InstantiateAsync combines load + Instantiate: unload with Addressables.ReleaseInstance(go) instead of Destroy. Addressables also has play mode scripts: Fast Mode (no bundle bake — fast iteration), Virtual Mode (simulated bundles), and Packed Play Mode (real bundles).

Async load flow

Code calls

Addressables.LoadAssetAsync("heroes/knight")

Check Cache

Already in memory?

Hit: instant
Load from source

Local bundle or CDN download

Deserialize

Decompress & create the object in memory

Callback

handle.Completed → result available

Release()

RefCount-- → 0 → unload from memory

Hands-on steps

1

Install Addressables

Window → Package Manager → search "Addressables" → Install. Window → Asset Management → Addressables → Groups to open the Groups window.

2

Mark an asset Addressable

Select it in the Project → Inspector → tick "Addressable" → set the address (e.g. "heroes/knight").

3

Configure Groups (Local vs Remote)

Addressables Groups window: Create New Group → set Build Path (Local or a Custom Remote Path for CDN). Drag assets into the group.

4

Build content

Addressables Groups → Build → New Build → Default Build Script. Build before Play or a real game build.

5

Load and Release correctly

LoadAssetAsync or InstantiateAsync with the address. Keep the handle. When done: Release(handle) or ReleaseInstance(go).

Interactive simulator

Simulate the async load flow — watch Reference Count and the Memory Pool.

Press Load to begin...

Loaded

0

Total Refs

0

Memory ~

0 MB

Code example

Basic

Load a prefab asynchronously and Instantiate — using await (C# async/await).

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using System.Threading.Tasks;

public class AssetLoader : MonoBehaviour
{
  AsyncOperationHandle<GameObject> knightHandle;

  async void Start()
  {
      // Async load — does not block the main thread
      knightHandle = Addressables.LoadAssetAsync<GameObject>("heroes/knight");
      await knightHandle.Task; // Or .Completed callback

      if (knightHandle.Status == AsyncOperationStatus.Succeeded)
      {
          Instantiate(knightHandle.Result, transform.position, Quaternion.identity);
      }
  }

  void OnDestroy()
  {
      // REQUIRED: Release to avoid a memory leak
      if (knightHandle.IsValid())
          Addressables.Release(knightHandle);
  }
}

// Or InstantiateAsync (auto-managed lifecycle)
async void SpawnEnemy(string address, Vector3 pos)
{
  var handle = Addressables.InstantiateAsync(address, pos, Quaternion.identity);
  await handle.Task;
  // When the enemy dies: Addressables.ReleaseInstance(go) instead of Destroy
}

Code example

Advanced

Load many assets at once by Label and preload the next scene in the background.

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

public class AssetManager : MonoBehaviour
{
  readonly List<AsyncOperationHandle> handles = new();

  // Load every asset labeled "ui_icons" at once
  async Task LoadUIIcons()
  {
      var handle = Addressables.LoadAssetsAsync<Sprite>(
          "ui_icons",
          sprite => { Debug.Log($"Loaded: {sprite.name}"); }
      );
      await handle.Task;
      handles.Add(handle);
  }

  // Preload the next scene in the background while the player is in-game
  AsyncOperationHandle<UnityEngine.ResourceManagement.ResourceProviders.SceneInstance> sceneHandle;

  public async void PreloadNextScene(string sceneAddress)
  {
      sceneHandle = Addressables.LoadSceneAsync(sceneAddress,
          UnityEngine.SceneManagement.LoadSceneMode.Additive,
          activateOnLoad: false); // Load but do not activate yet
      await sceneHandle.Task;
      Debug.Log("Scene preloaded, waiting for activation");
  }

  public async void ActivatePreloadedScene()
  {
      await sceneHandle.Result.ActivateAsync();
  }

  void OnDestroy()
  {
      foreach (var h in handles)
          Addressables.Release(h);
  }
}

📌 Quick recap

  • LoadAssetAsync = non-blocking load; returns a Handle
  • Release(handle) is required when done — avoid leaks
  • InstantiateAsync + ReleaseInstance instead of Instantiate/Destroy
  • Label = load many assets at once by group
  • Fast Mode: development (fast); Packed Mode: real bundle test

⚠️ Common mistakes

  • ❌ Never Release the handle → serious memory leak

    The asset stays in RAM; reference count never hits 0

    ✅ Always Release in OnDestroy, always keep the handle

  • ❌ Exception: Attempting to use an invalid operation handle

    Using a handle after Release, or double-release

    ✅ Check handle.IsValid() before Release; null the handle after