Quick answer: Hold every AsyncOperationHandle as a class field; call Addressables.Release(handle) in OnDestroy. For instantiated prefabs use Addressables.ReleaseInstance(go), which both destroys and decrements. Drop a handle without releasing and you leak the asset for the session.
Game runs fine for ten minutes. Then memory creeps. Then a Bundle Failed To Mount crash on Android. Addressables holds refcounts behind handles, and forgotten handles never decrement.
The Symptom
Memory grows over time even though gameplay should free assets. Editor Addressables window shows hundreds of loaded assets that should be gone. Console may print “Cannot release a null Asset Bundle” warnings.
The Fix Pattern
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class EnemyLoader : MonoBehaviour
{
public AssetReferenceGameObject enemyRef;
private AsyncOperationHandle<GameObject> _handle;
private GameObject _instance;
async void Start()
{
_handle = enemyRef.InstantiateAsync(transform);
_instance = await _handle.Task;
}
void OnDestroy()
{
if (_instance != null)
Addressables.ReleaseInstance(_instance);
}
}
One handle stored, one release in OnDestroy.
For Plain Asset Loads
private AsyncOperationHandle<Texture2D> _texHandle;
async Task LoadIcon()
{
_texHandle = Addressables.LoadAssetAsync<Texture2D>("icons/sword");
var tex = await _texHandle.Task;
iconImage.texture = tex;
}
void OnDestroy()
{
Addressables.Release(_texHandle);
}
Detecting Leaks
Addressables → Profiler → Asset Manager. Hierarchical view of every loaded asset and its refcount. Numbers that grow without an obvious owner are leaks.
Project Settings → Addressables → tick “Log Runtime Exceptions” and “Send Profiler Events.” Now leaked handles produce console warnings on application quit, which catches them in development builds.
Pool Pattern for Frequent Loads
For projectiles or enemies you load thousands of times, use addressables once to load the prefab handle, then pool the instances yourself with Object.Instantiate. Release the prefab handle on level unload.
Verifying
Load a scene that uses Addressables, unload it, GC, check Profiler → Memory. Resources should drop. Repeat 10x; memory should stabilize. If it grows linearly, something isn’t releasing.
“Hold the handle. Release in OnDestroy. ReleaseInstance for instantiated. Memory stays flat.”
Related Issues
For Addressables remote cache stale, see cache stale. For asmdef circular, see asmdef.
Hold. Release. Refcount returns to zero.