Unity Addressables
Minh Khoa
Author
Unity Addressables (From Basics to Advanced)
1. Overview (Introduction)
Addressable Asset System (or Addressables) is a package developed by Unity itself that provides an easy way to load assets by "address" (address). This system solves the complex issues of AssetBundles (dependencies) while still delivering the power of memory management, remote loading (remote loading) and content updates (content update) flexibly.
2. Core Differences: Addressables, Resources, and AssetBundles
Many programmers like to use Addressables even when the game is in Offline format (Local only) for the purpose of Lazy Load to prevent stuttering (bottleneck). Below is a detailed comparison when used in Local mode:
Storage state (Hard drive / Disk)
- Resources: All assets in the Resources folder will be lumped together into very large monolithic files in the format
resources.assets(hidden inside the installation package APK/IPA). - Addressables (Local): Assets are packaged into many neat file fragments AssetBundles neatly and automatically placed into a designated folder (usually
StreamingAssets).
When the Game has just started (RAM & Startup Speed)
- Resources: As soon as the game flashes up, Unity immediately forces the OS to read and load the entire folder tree (Index/Catalog) of
resources.assetsand structure it into RAM. The more stuff you stuff into Resources, the longer the black screen lasts when you start the game. The amount RAM this index storage will be permanently occupied and cannot be freed. - Addressables: Unity only loads a tiny Map Catalog list containing addresses. The game opens instantly even if the project has 100 or 100.000 files. When Load has not been performed yet, the asset is completely asleep on the hard drive (Disk) not consuming a single byte RAM at all.
Asset Loading Process (Prevent Bottleneck / Hitches)
- Resources: Has the command
Resources.Load()with the characteristic Synchronous (Synchronous). It will force the (Main Thread) to freeze 100% while waiting for it to find the file > read the disk > decompress > inject into RAM. This is the biggest cause of Bottleneck (bottleneck), frame drops FPS, stuttering frames when spawning monsters, levels. - Addressables: Carries the nature of Lazy Load & Asynchronous (Asynchronous). When you call the command,
LoadAssetAsyncthe work of opening the read stream I/O from the hard drive and decompressing is handled silently on a (Worker Thread). FPS while your game remains completely smooth. After reading from Disk, it brings that Object up RAM and then creates it for you to use through Callback logic.
Unload Process (Memory release RAM)
- Resources: After assets are brought up RAM they are only fully reclaimed when moving to a new Scene, or by using the command
Resources.UnloadUnusedAssets(). The process of this function is to periodically scan and compare the entire memory space of the Game again, causing the main thread to hitch heavily. - Addressables: The release process RAM is handled through Reference Counting (Reference Counting) interwoven at a micro scale. Call
Addressables.Releasethe system will immediately clean that file out of RAM instantly, independently, and without causing system stutter.
The difference with AssetBundles: Addressables is developed around the core ecosystem of the model AssetBundle. Think of Addressables as the highest-level "Manager Layer" (Manager Layer)", handling for you the procedures from creating Bundles, saving the Catalog, dealing with overlapping Dependency flows, automatically releasing when the object is Destroyed... If you use AssetBundles the original primitive
, you would have to spend weeks coding a very large Framework from scratch to do these things. (3. Core Concepts)
- Core ConceptsAddress
Assets/Models/Characters/Player.prefab: The unique identifier string of the Asset. Instead of a cumbersome path"PlayerPrefab". - AssetReference, you only need to call it briefly (: A kind of variable that lets you directly reference an Addressable Asset through the Inspector by drag-and-drop, instead of having to type the Address string by hand).
- to avoid typosLabel
- **: A classification label. Very useful when you want to load a group of assets at once. For example: label all monsters and sounds of Level 1 with "Level1", then call one piece of code to load everything.**Group AssetBundles (: Assets will be grouped into Groups. At build time, the Group's Settings will determine how the Asset is compressed into)For example: Group A into bundle A, Group B into bundle B
- **. Groups can be configured as Local or Remote.**Profile (: Allows you to set up) Path CDN corresponding to development stages. For example, the "Dev" Profile points to localhost, while the "Production" Profile points to
the actual game path. (4. Basic Setup)
- Getting Started
Windows -> Package Manager -> Addressables-Install via Package Manager: - > Install.
Window -> Asset Management -> Addressables -> GroupsInitialize Addressables Settings: OpenCreate Addressables Settings, clickAddressableAssetsData. - . Unity will automatically create the folder
- Mark the Asset: There are 2 ways to turn an Asset into Addressables:
AddressableCheck the tick box - at the top of the Inspector panel when you click that Asset.
Addressables Groups.
- Mark the Asset: There are 2 ways to turn an Asset into Addressables:
Drag and drop the Asset directly into the (5. Basic Usage)
Basic Usage (Initialization)
Although Addressables can automatically initialize in the background when you call the first load command, at practical scale it is better to proactively initialize before loading the screen:
using UnityEngine.AddressableAssets;
void Start() {
Addressables.InitializeAsync().Completed += handle => {
Debug.Log("Khα»i tαΊ‘o Addressables thΓ nh cΓ΄ng!");
};
}
Load an Asset (Load Asset)
After loading the asset into RAM (but not yet spawned in the Scene):
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class AddressableExample : MonoBehaviour
{
public string address = "MyCube";
void Start() {
// TαΊ£i khΓ΄ng Δα»ng bα» Δα» k khα»±ng game
Addressables.LoadAssetAsync<GameObject>(address).Completed += OnLoadDone;
}
private void OnLoadDone(AsyncOperationHandle<GameObject> obj) {
if (obj.Status == AsyncOperationStatus.Succeeded) {
GameObject loadedPrefab = obj.Result;
// TiαΊΏn hΓ nh sinh ra scene
Instantiate(loadedPrefab);
} else {
Debug.LogError("Lα»i khi load asset!");
}
}
}
Direct instantiation (Instantiate Asset)
Load and automatically create the Scene at the same time:
Addressables.InstantiateAsync("MyCube").Completed += (handle) => {
// Δược gα»i khi Instantiate xong. handle.Result chΓnh lΓ GameObject ΔΓ£ cΓ³ trΓͺn scene.
GameObject myCubeInstance = handle.Result;
};
Use AssetReference (Recommended)
Avoid mistyping the Address string:
public AssetReference playerPrefabRef;
void LoadPlayer() {
playerPrefabRef.InstantiateAsync().Completed += (handle) => {
Debug.Log("Player spawned thΓ nh cΓ΄ng thΓ΄ng qua Asset Reference.");
};
}
6. Memory Management (Memory Management - EXTREMELY IMPORTANT)
Addressables uses the Reference Counting (Reference Counting) mechanism (to release memory. When the reference count) ref count RAM (returns to 0, the asset will be destroyed from).
- unload
LoadAssetAsyncEach time you call - , the ref count increases by 1.
InstantiateAsyncEach time you call
, the ref count increases by 1 AND its original asset also increases by 1. GOLDEN RULE: (Initialize however you like, then Release) Release
// TrΖ°α»ng hợp 1: NαΊΏu xΓ i LoadAssetAsync
AsyncOperationHandle<GameObject> handle = Addressables.LoadAssetAsync<GameObject>("MyUI");
// --> Khi khΓ΄ng cαΊ§n dΓΉng Prefab ΔΓ³ nα»―a:
Addressables.Release(handle);
// TrΖ°α»ng hợp 2: NαΊΏu xΓ i InstantiateAsync
AsyncOperationHandle<GameObject> handleInst = Addressables.InstantiateAsync("MyEnemy");
GameObject enemyInstance = handleInst.Result;
// --> Khi quΓ‘i chαΊΏt, TUYα»T Δα»I KHΓNG DΓNG Destroy(enemyInstance) trα»±c tiαΊΏp bαΊ±ng script cΖ‘ bαΊ£n cα»§a Unity.
// --> CΓ‘ch ΔΓΊng Δα» Addressable tα»± giαΊ£m count vΓ gom rΓ‘c:
Addressables.ReleaseInstance(enemyInstance);
// hoαΊ·c Addressables.ReleaseInstance(handleInst);
with the corresponding function for that method. (7. Advanced Concepts for Pro Level)
Advanced Concepts (Load by Label)
When you want to load 10 types of weapons labeled "Weapon" at once:
// HΓ m callback tα»«ng phαΊ§n tα» load xong Δược truyα»n vΓ o tham sα» thα»© 2
Addressables.LoadAssetsAsync<GameObject>("Weapon", (loadedWeapon) => {
// Giao diα»n: Update thanh loading (% progress) α» ΔΓ’y
Debug.Log("Loaded tα»«ng phαΊ§n: " + loadedWeapon.name);
}).Completed += (handle) => {
// KΓch hoαΊ‘t khi TOΓN Bα» weapon ΔΓ£ load xong
IList<GameObject> allWeapons = handle.Result;
};
Play Mode Scripts (Play mode in the Editor)
In the window Addressables Group -> Play Mode Script (the top toolbar), there are 3 test modes:
- Use Asset Database (Fast Mode): Fastest execution, copies directly from disk without caring about Addressable config (does not create Bundle). For code / logic testing.
- Simulate Groups (Virtual Mode): The most important. Simulates network-delayed loading and strictly follows bundle separation, but still runs fast without needing a real build. Ideal for checking memory leaks and the (flow) of loading.
- Use Existing Build: You must first manually trigger the command
Build -> New Buildin the Groups window group. The game runs exactly like on a real device.
Handling Remote Content Updates (Remote/CDN - Game Update System)
Addressables lets you push assets to Host/CDN. The next time you launch the game, it updates automatically without requiring a new App Store download. APK/AAB In Profile, adjust
- to point to your server
RemoteLoadPathfor example: (In the group containing the asset, adjusthttp://mygame.com/[BuildTarget]). - to
Build PathandRemoteBuildPathtoLoad PathEnable the optionRemoteLoadPath. - in Addressable Asset Settings.
Build Remote CatalogCode approach for the update-check process: - Get size & Downloading screen
// B1: Kiα»m tra xem cΓ³ bαΊ£n cαΊp nhαΊt catalog (thΓ΄ng tin phiΓͺn bαΊ£n gα»c) mα»i khΓ΄ng
Addressables.CheckForCatalogUpdates().Completed += (checkForUpdateHandle) => {
if (checkForUpdateHandle.Result.Count > 0) {
// B2: CαΊp nhαΊt catalog
Addressables.UpdateCatalogs(checkForUpdateHandle.Result).Completed += (updateHandle) => {
// Danh sΓ‘ch cΓ‘c ID cαΊ§n tαΊ£i mα»i. Δem danh sΓ‘ch nΓ y Δi call hΓ m Download... α» mα»₯c dΖ°α»i
var locators = updateHandle.Result;
};
}
};
The code for making a loading bar with size
- Best Practices & Performance Optimization (MB):
public IEnumerator CheckAndDownload(string labelToDownload) {
// B1: Check dung lượng
var sizeHandle = Addressables.GetDownloadSizeAsync(labelToDownload);
yield return sizeHandle;
long totalBytes = sizeHandle.Result;
Addressables.Release(sizeHandle); // Done task size
if (totalBytes > 0) {
Debug.Log($"CαΊ§n tαΊ£i xuα»ng: {totalBytes / (1024f * 1024f):F2} MB");
// B2: TαΊ―t auto clear cache, tiαΊΏn hΓ nh Download
var downloadHandle = Addressables.DownloadDependenciesAsync(labelToDownload, false);
// VΓ²ng lαΊ·p lαΊ₯y % hiα»n thα» lΓͺn UI
while (!downloadHandle.IsDone) {
float percent = downloadHandle.GetDownloadStatus().Percent;
Debug.Log($"Δang tαΊ£i... {percent * 100:F0}%");
yield return null;
}
Addressables.Release(downloadHandle);
Debug.Log("TαΊ£i hoΓ n tαΊ₯t!");
} else {
Debug.Log("ΔΓ£ cΓ³ sαΊ΅n α» local bαΊ£n mα»i nhαΊ₯t, vΓ o thαΊ³ng game.");
}
}
Optimize (Asset Duplication)
-
Avoid duplicating assets and wasting space (Wasteful scenario)
- : Prefab Ais in Group 1 (and Prefab B) is in Group 2 (both use the same) is not added to Addressable Material_C (. When building, Unity implicitly copies)into 2 copies and puts them into 2 different groups Material_C > Bloated size. -Fix
- : Double-click on the Tool> Run the rule
Analyze(Window -> Asset Management -> Addressables -> Analyze) -"Check Duplicate Bundle Dependencies" . Strictly follow this rule; if there are duplicate shared resources, create 1to put theGroup_SharedResourcethat Material_C into it.
-
How to structure Groups (Granularity)
- Do not put everything into one giant Group: Hard to update small parts, wastes memory because you accidentally load things not used on the current screen.
- Do not split every asset into a different Group: The initial loading process is slow due to the overhead of scanning each file from the OS.
- Standard strategy: Split by Lifetime (Audio_Group, UI_Global_Group load once and live for the entire lifetime) or split by Feature Cluster / Screen Type (Level_Forest_Group, IAP_Popups_Group,...).
-
Be careful with Synchronous (Synchronous)
- From the Addressables Unity releases 1.17+, Unity supports
Addressables.LoadAssetAsync().WaitForCompletion(). It will block the main thread (freeze the game) until the file finishes downloading. - Recommendation: Only use this on very small local files or when thread blocking is truly needed. Absolutely do not use it if the file is on Remote CDN.
- From the Addressables Unity releases 1.17+, Unity supports
-
Bottleneck UniTask (Recommended)
- Listening to events
.Completedwith delegates sometimes creates callback hell (messy, hard-to-read indented code). Integrate the library UniTask to program it into a flowawaitwith an extremely beautiful outline:
- Listening to events
// DΓΉng UniTask tiαΊΏt kiα»m hΓ ng tΓ‘ code
GameObject prefab = await Addressables.LoadAssetAsync<GameObject>("Player");
GameObject target = await Addressables.InstantiateAsync(prefab);
9. Conclusion
Addressables is the heart of professional Unity game development and a LiveOps modern system. In summary, the operating philosophy is:
- Completely abandon the system
Resources/. - Divide resources into Groups scientifically.
- Anything that is uploaded (
Load/Instantiate) -> Must definitely be thrown away (Release/ReleaseInstance) when no longer in use! - Take advantage of Remote Catalog & AssetBundle Update to create an OTA update download mechanism without depending on the review step on Apple App (Over-The-Air) Play. Store/CH I hope this guide will become a solid compass on your journey to becoming the king of Unity Addressables
Don't be afraid to experiment in Play Mode with the! Simulate Groups feature to completely master it.γγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγαγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγαγγγγγγγγγγγγγγγγρΏγγγγγγγγγγγγγγγγγγαγγγγοΈγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγοΌγγγγγγγγγγγγγγγγγγγγγγοΌγγγγβ¬γγγγγγγγγγαγγγγγγγγγγγγγβγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγΰ΅±γγγγβγγγΰΌγγγγγγγγγγγγγγγβ¬γγγγγγγγγοΌγγγγγγγγγγγγδγγγγγργγγγγγγγς¦¦¦γγγγγγγοΌγγγγβ¬γγγγγγγγγγοΌγγγγγγγγγγγγγγγγγγγγγγγγγγγγβ. ],