Unity的资源加载与卸载

Unity资源管理精要
本文深入探讨Unity中资源加载与卸载的三种方式,包括静态引用、Resources.Load及AssetBundle.Load,解析每种方式的特点与应用场景。同时,文章详细讲解资源占用内存的三种形式及如何有效管理内存,提供具体的加载与释放流程,帮助开发者优化Unity项目的资源管理。

 

Unity的资源加载与卸载

有三种资源加载方式:

1.静态引用。具体操作:创建public变量,把文件挂到物体上,在Inspector里把相应资源给public变量,用的时候instantiate或者直接用。

2.Resources.Load。加载Resources文件夹下的资源,加载后instantiate.

3.AssetBundle.Load。加载打包后的资源。

前两种资源加载方式,对于引用对象是在instantiate时加载的,而不是在加载时直接加载的,所以有时会造成第一次加载时客户端卡。

第三种资源加载方式,在加载时会加载所有引用资源,instantiate时只是生成克隆。

 

说到Unity资源的卸载,就需要先了解要卸载什么。其实就是要卸载资源所占用的内存,使资源占用的内存释放。

资源所占用内存的形式一般是三种:

1.assetbundle文件内存镜像占用的内存,在加载assetbundle文件完成后,会在内存中形成assetbundle文件的内存镜像,同一个assetbundle文件不能有两个内存镜像,所以同一个assetbundle文件在没有Unload之前不能再次加载。

2.从assetbundle文件中加载出来的资源所占的内存(AssetBundle.Load多次Load只会有一份资源内存占用)。(指GameObject,Texture,Sprite,Shader,Material)如果从assetbundle里加载的资源是引用类型的,就不需要实例化就可以直接使用,并且如果有多个地方使用同一个引用资源时,引用资源不需要实例化,比如:Texture,Sprite,Shader,Material就是引用类型的。如果assetbundle里加载的资源不是引用句类型,不能直接使用,需要实例化后使用,如:GameObject,需要Instantiate实例化后使用。如果需要多个GameObject,需要多次实例化。

3.Instantiate实例化的资源所占用的内存。(一般是指GameObject)

AssetBundle.UnLoad(false);卸载1的内存占用。

AssetBundle.UnLoad(true);卸载1,2的内存占用(所有此AssetBundle已经加载的资源)。

如果想要只卸载某个已经加载的资源,用Resources.UnLoadAsset(obj)(只能用这个卸载引用资源);Resources.UnloadUnusedAsset()卸载没有被引用的所有的资源。

Destroy主要用来销毁3的内存占用,即销毁克隆对象,也可用于销毁静态物体,不会自动释放该对象的所有引用。Destroy不能用来销毁从文件加载的资源(会删除相应的资源文件,报错Destroying assets is not permitted to avoid data loss.)

加载新场景时会自动销毁2,3的内存占用,但是1的内存占用不会销毁,1只能通过AssetBundle.Unload去释放。

一般的加载流程:

  1.创建assetbundle(WWW www = new WWW(url))

  2.用AssetBundle.Load加载需要的资源

  3.判断资源的种类,根据种类去选择下一步操作(可把资源分为共享资源和非共享资源,或者根据使用频率选择是否保存已经加载过的资源等)

  4.确保加载完成后,调用AssetBundle.Unload(false)去卸载1创建出的镜像文件。

一般的释放流程:

  1.如果克隆了对象,用Destroy去销毁。

  2.在合适的地方调用Resources.UnloadUnusedAsset(),释放已经没有引用的资源(就是没有地方在用的资源,引用计数为0)

  3.如果是想卸载单独的一个用Load加载的资源,用Resources.UnloadAsset(obj)释放(只能用这个卸载引用资源)

  4.如果想要立即释放调用GC.Collect()。

一个容易出错的例子:

UnityEngine.Object obj = Resources.Load("MyPrefab");

GameObject instance = Instantiate(obj) as GameObject;
Destroy(instance);
Resources.UnloadUnusedAssets();

这时,内存并没有释放掉,因为MyPrefab还被obj这个变量所这用。

obj = null;

Resources.UnloadUnusedAssets();

这样才能真正释放

Resources.UnloadUnusedAssets()不但要没有实际物体引用,也要没有被生命周期内的变量所引用,才可以释放。

<think>首先,用户的问题是关于在Unity中使用Addressable Assets加载卸载场景的具体方法。用户提到了几个引用,所以我需要基于这些引用来提供准确的信息。 回顾引用内容: - 引用[1]:指出必须调用 `Addressables.Release` 来释放加载资源,除非使用 `Addressables.InstantiateAsync` 并设置 `trackHandle` 为 true(默认值)。 - 引用[2]:强调内存管理的关键是成对调用加载卸载方法。释放时可以使用加载好的资源或操作句柄。 - 引用[3]:提到Addressables的使用简单,可以无缝替换原有的加载模式。 - 引用[4]:是关于AssetBundle的设置,如Packing Mode和路径。 用户的核心问题是:加载卸载Addressable Assets中的场景的方法。 从引用[1]和[2]中提取关键点: - 加载场景:使用Addressables API,如 `Addressables.LoadSceneAsync` 方法来加载场景。 - 卸载场景:必须调用 `Addressables.Release` 或相关方法来释放资源。释放时可以使用操作句柄或资源实例。 具体步骤: 1. **加载场景**: - 使用 `Addressables.LoadSceneAsync` 方法加载场景。这个方法返回一个 `AsyncOperationHandle<SceneInstance>` 对象。 - 例如:`var asyncOperationHandle = Addressables.LoadSceneAsync("sceneKey");` 2. **卸载场景**: - 必须释放加载的场景资源。调用 `Addressables.Release` 方法。 - 参数可以是操作句柄(`asyncOperationHandle`)或场景实例(`asyncOperationHandle.Result`)。 - 例如:`Addressables.Release(asyncOperationHandle);` 或 `Addressables.Release(sceneInstance);` 引用[1]提到,对于 `InstantiateAsync` 设置 `trackHandle` 为 true 会自动释放,但这里是针对场景加载,通常使用 `LoadSceneAsync`。 引用[2]明确说明对于场景加载,释放时可以使用句柄或实例。 用户可能的需求:提供一个清晰的、逐步的指南。 回答结构: - 保持结构清晰,帮助用户逐步解决问题。 - 使用中文回答。 - 引用末尾添加引用标识,如 [^1]。 - 生成相关问题。 系统级指令: - 行内数学表达式用 `$...$`,但这里可能不涉及数学公式。 - 独立公式用 `$$...$$`,但本问题不需要公式。 - LaTeX语法正确。 - 生成相关问题。 最终回答应包括: 1. **加载场景的方法**。 2. **卸载场景的方法**。 3. **注意事项**,如内存管理。 4. **示例代码**(如适用)。 5. **相关问题**。 示例代码:由于是Unity脚本,用代码块展示。 参考引用添加: - 在相关部分末尾添加 [^1], [^2] 等。 完整回答: - 先解释加载方法。 - 然后卸载方法。 - 强调成对调用的重要性。 相关问题生成: - 基于主题,如优化、常见问题等。 </think>在 Unity 中使用 Addressable Assets 加载卸载场景时,核心是遵循“加载卸载成对”的内存管理原则,以避免内存泄漏。以下是基于 Unity Addressables 系统的最佳实践方法,参考了您提供的引用内容。我会逐步解释加载卸载场景的具体步骤、代码示例以及注意事项。 ### 1. **加载场景的方法** 加载 Addressable 场景使用 `Addressables.LoadSceneAsync` 方法,它返回一个 `AsyncOperationHandle<SceneInstance>` 句柄。这个句柄用于跟踪加载状态和后续卸载。 - **步骤**: 1. 使用 `Addressables.LoadSceneAsync` 加载场景资源。 2. 指定场景的 key(例如场景的 Addressable 路径或标签)。 3. 设置加载模式(如加载后是否激活场景)。 - **代码示例**: ```csharp using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations; using UnityEngine.ResourceManagement.ResourceProviders; using UnityEngine.SceneManagement; public class SceneLoader : MonoBehaviour { // 场景的 Addressable 键(key),例如:"Assets/Scenes/MyScene.unity" public string sceneKey; private AsyncOperationHandle<SceneInstance> _sceneHandle; void Start() { // 加载场景:加载但不立即激活(LoadMode.Single 表示替换当前场景) _sceneHandle = Addressables.LoadSceneAsync(sceneKey, LoadSceneMode.Single, false); _sceneHandle.Completed += OnSceneLoaded; } void OnSceneLoaded(AsyncOperationHandle<SceneInstance> handle) { if (handle.Status == AsyncOperationStatus.Succeeded) { // 加载成功后,可以选择激活场景 SceneInstance sceneInstance = handle.Result; sceneInstance.ActivateAsync(); Debug.Log("场景加载成功!"); } else { Debug.LogError($"场景加载失败:{handle.OperationException}"); } } } ``` - **解释**: - `LoadSceneAsync` 的第三个参数 `false` 表示加载后不自动激活,允许你手动控制激活时机。 - 使用 `Completed` 事件处理加载结果,确保错误处理。 - 加载后,场景资源被缓存,但必须显式卸载 [^2]。 ### 2. **卸载场景的方法** 卸载场景必须调用 `Addressables.Release` 来释放资源,否则会导致内存泄漏(引用[1])。释放时可以使用加载句柄(`AsyncOperationHandle`)或场景实例(`SceneInstance`)。 - **步骤**: 1. 确保场景不再需要(例如,切换场景时)。 2. 调用 `Addressables.Release` 释放资源。 3. 可选:卸载场景资源后,触发垃圾回收。 - **代码示例**: ```csharp public void UnloadScene() { // 方法1:使用加载句柄卸载 Addressables.Release(_sceneHandle); Debug.Log("场景资源已释放!"); // 方法2:使用场景实例卸载(如果已获取 SceneInstance) // Addressables.Release(_sceneHandle.Result); } ``` - **注意事项**: - **成对调用**:加载卸载必须配对。例如,在场景切换或对象销毁时调用卸载方法(如 `OnDestroy` 中)[^2]。 - **自动释放例外**:仅当使用 `Addressables.InstantiateAsync` 实例化对象且 `trackHandle` 为 true(默认值)时,资源会自动释放。但场景加载使用 `LoadSceneAsync`,必须手动释放 [^1]。 - **避免多次释放**:同一句柄多次调用 `Release` 会导致错误,检查句柄状态(如 `_sceneHandle.IsValid()`)。 ### 3. **关键注意事项** - **内存管理**:Addressables 不会自动释放加载资源(除非特定例外),必须显式调用 `Release`。遗漏卸载会造成内存泄漏 [^1][^2]。 - **句柄重用**:卸载后,句柄变为无效。重新加载同一场景时,需要重新调用 `LoadSceneAsync`。 - **性能优化**:频繁加载/卸载大场景可能影响性能。建议使用引用计数或对象池管理资源 [^2]。 - **无缝迁移**:从 Unity 的 `Resources` 或 AssetBundle 切换到 Addressables 时,代码兼容性好,无需重大修改 [^3]。 ### 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值