关于 Unity Addressables
面向需要异步加载、分组管理、内存管理或远程内容的开发者,介绍如何使用 Unity Addressables 管理资源。还涵盖从 Resources.Load 迁移,以及释放句柄以避免内存泄漏。
主要功能
- 01异步加载资源
- 02按组和标签组织资源
- 03带进度预加载资源
- 04管理句柄与引用计数
- 05通过 Addressables 加载场景
- 06从 Resources.Load 迁移
适用场景
- 01在 Unity 项目中按需加载资源
- 02管理可选内容或场景专属内容
- 03通过释放句柄避免内存泄漏
- 04将现有 Resources.Load 用法迁移到 Addressables
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ juliankerignard/ unity-skills --skill unity-addressables安装后在 Claude Code 中输入/unity-addressables确认已加载。
附带文件references/addressables-patterns.md
详细介绍
Unity Addressables
此技能的功能
指导如何使用 Addressables 系统进行异步资源加载、分组组织、内存管理和远程内容(CDN/DLC)管理。涵盖从 Resources.Load 迁移、带进度的预加载、引用计数,以及避免内存泄漏的释放模式。
前提条件
- 通过 Package Manager 安装
com.unity.addressables包
快速开始
- 安装包:Window > Package Manager > Unity Registry > Addressables
- 打开 Window > Asset Management > Addressables > Groups
- 将资源标记为“Addressable”(Inspector 中的复选框)
- 按逻辑组织分组(按功能、场景或下载内容)
- 使用
Addressables.LoadAssetAsync<T>加载
决策树
Comment charger cet asset ?
|
+-- Toujours en memoire, reference directe dans l'Inspector ?
| --> Reference directe [SerializeField] (pas besoin d'Addressables)
|
+-- Charge a la demande, connu au compile-time ?
| --> AssetReference dans l'Inspector + LoadAssetAsync
|
+-- Charge dynamiquement par label/nom ?
| --> Addressables.LoadAssetsAsync avec label
|
+-- Contenu telechargeable (DLC, patches) ?
| --> Remote group + catalog update
|
+-- Migration depuis Resources.Load ?
--> Marquer les assets comme Addressable, remplacer Resources.Load par LoadAssetAsync
分步指南
Step 1:分组组织
- 按功能分组:
Characters、Levels、UI、Audio - 按下载内容分组:
Core(包含在构建中)、Optional(可下载) - 如果按场景加载,则按场景分组
- 避免分组过大(> 50 MB):按用途拆分为子组
- 使用标签标记跨组资源(
level1、boss、tutorial)
Step 2:使用句柄异步加载
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class AssetLoader : MonoBehaviour
{
[SerializeField] private AssetReference prefabRef;
private AsyncOperationHandle<GameObject> handle;
public async Awaitable<GameObject> LoadAndInstantiateAsync()
{
handle = Addressables.LoadAssetAsync<GameObject>(prefabRef);
await handle.Task;
if (handle.Status == AsyncOperationStatus.Succeeded)
return Instantiate(handle.Result);
Debug.LogError($"Failed to load: {prefabRef}");
return null;
}
private void OnDestroy()
{
// CRITIQUE: toujours release le handle
if (handle.IsValid())
Addressables.Release(handle);
}
}
要点:
- 在 Inspector 中使用
AssetReference,避免使用魔法字符串 - 使用
await handle.Task等待加载完成 - 使用
handle.Result前,务必检查handle.Status - 在
OnDestroy中调用Release,以避免泄漏
Step 3:按标签加载
public class LabelLoader : MonoBehaviour
{
[SerializeField] private AssetLabelReference labelRef;
private AsyncOperationHandle<IList<GameObject>> handle;
public async Awaitable<IList<GameObject>> LoadAllAsync()
{
handle = Addressables.LoadAssetsAsync<GameObject>(labelRef, null);
await handle.Task;
if (handle.Status == AsyncOperationStatus.Succeeded)
return handle.Result;
Debug.LogError($"Failed to load label: {labelRef}");
return null;
}
private void OnDestroy()
{
if (handle.IsValid())
Addressables.Release(handle);
}
}
Step 4:从 Resources.Load 迁移到 Addressables
// AVANT (synchrone, tout en memoire au build)
var prefab = Resources.Load<GameObject>("Enemies/Goblin");
// APRES (async, charge a la demande)
var handle = Addressables.LoadAssetAsync<GameObject>("Enemies/Goblin");
await handle.Task;
var prefab = handle.Result;
// ... utiliser prefab ...
Addressables.Release(handle);
迁移步骤:
- 将资源移出
Resources/文件夹 - 将每个资源标记为 Addressable(Inspector 复选框)
- 确认 address 与原来的
Resources/路径一致 - 将
Resources.Load<T>(path)替换为Addressables.LoadAssetAsync<T>(address) - 不再需要资源时,添加
Release() - 迁移完成后,删除
Resources/文件夹
Step 5:Addressables 场景
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.ResourceProviders;
public class SceneLoader : MonoBehaviour
{
[SerializeField] private AssetReference sceneRef;
private AsyncOperationHandle<SceneInstance> sceneHandle;
public async Awaitable LoadSceneAsync()
{
sceneHandle = Addressables.LoadSceneAsync(sceneRef);
await sceneHandle.Task;
}
public async Awaitable UnloadSceneAsync()
{
if (sceneHandle.IsValid())
{
await Addressables.UnloadSceneAsync(sceneHandle).Task;
}
}
}
严格规则
- 始终在不再需要资源时调用
Addressables.Release(handle) - 始终在 Inspector 中使用
AssetReference(不要硬编码 string addresses) - 始终处理加载失败的情况(
handle.Status) - 始终对通过
InstantiateAsync创建的对象使用Addressables.ReleaseInstance(),而不是Destroy() - 绝不在新项目中使用
Resources.Load(使用 Addressables) - 绝不保留未释放的句柄(会导致内存泄漏)
- 绝不在没有引用计数的情况下重复加载同一资源
- 优先使用
AssetReferenceT<T>对引用进行类型化(AssetReferenceGameObject、AssetReferenceSprite等) - 优先使用 Inspector 中的
AssetLabelReference,而不是标签字符串
相关技能
/perf-audit:检测内存泄漏和未释放的资源/unity-build-config:构建内容和远程目录/unity-code-gen:生成加载系统和资源管理器
故障排查
| 问题 | 解决方案 |
|---|---|
| "InvalidKeyException" | 地址或标签不存在。请在 Addressables Groups window 中检查 |
| 内存泄漏 | 忘记调用 Release()。请使用 Addressables Profiler(Event Viewer) |
| 构建不包含资源 | 资源不属于任何组,或该组未包含在构建中 |
| 加载缓慢 | 组过大。请按用途拆分为多个子组 |
| "Cannot instantiate" | 资源不是预制件,或加载失败(请检查 Status) |
| "Exception during init" | Addressables 尚未初始化。请先调用 Addressables.InitializeAsync() |
| 资源重复 | 某个资源属于多个组。请使用 Build Report 检测 |
| 远程目录未更新 | 启动时调用 CheckForCatalogUpdates,然后调用 UpdateCatalogs |
评论
支持 Markdown