Unity Addressable:不加载至RAM获取所有资源位置并存入列表
Addressable地图资源按需加载与内存优化方案
问题根源分析
- 你当前的代码仅释放了实例化操作的句柄,但没有销毁场景中实例化出的GameObject,导致这些实例一直占用内存。
- 通过
new AssetReference(location.PrimaryKey.ToString())创建的AssetReference未被正确管理,可能造成资源引用残留。 - 提前实例化所有资源违背了“按需加载”的初衷,直接导致内存过载。
核心优化思路
- 仅预加载资源位置信息,不提前加载任何资源本体
- 玩家靠近时才实例化对应区块,远离时立即销毁实例并释放资源
- 严格管理异步操作句柄与资源引用的生命周期
优化后的代码实现
using System.Collections.Generic; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations; public class MapChunkLoader : MonoBehaviour { // 存储所有地图区块的资源位置与初始坐标 private List<(IResourceLocation location, Vector3 position)> _mapChunkData = new(); // 记录已加载的区块实例与对应的操作句柄 private Dictionary<IResourceLocation, (GameObject instance, AsyncOperationHandle<GameObject> handle)> _loadedChunks = new(); private void Start() { StartCoroutine(PreloadMapLocations()); } // 预加载所有地图资源的位置信息,不加载资源本身 private IEnumerator PreloadMapLocations() { var loadLocationsOp = Addressables.LoadResourceLocationsAsync("map"); yield return loadLocationsOp; if (loadLocationsOp.Status == AsyncOperationStatus.Succeeded) { foreach (var location in loadLocationsOp.Result) { // 临时加载资源获取初始坐标,之后立即释放 var tempLoadOp = Addressables.LoadAssetAsync<GameObject>(location); yield return tempLoadOp; if (tempLoadOp.Status == AsyncOperationStatus.Succeeded) { _mapChunkData.Add((location, tempLoadOp.Result.transform.position)); Addressables.Release(tempLoadOp); } } } // 释放资源位置列表的加载句柄 Addressables.Release(loadLocationsOp); } // 玩家靠近时调用:加载指定地图区块 public void LoadMapChunk(IResourceLocation location) { if (_loadedChunks.ContainsKey(location)) return; var instantiateOp = Addressables.InstantiateAsync(location); instantiateOp.Completed += op => { if (op.Status == AsyncOperationStatus.Succeeded) { var instance = op.Result; var chunkData = _mapChunkData.Find(d => d.location == location); instance.transform.position = chunkData.position; _loadedChunks.Add(location, (instance, op)); } }; } // 玩家远离时调用:卸载指定地图区块 public void UnloadMapChunk(IResourceLocation location) { if (_loadedChunks.TryGetValue(location, out var chunkData)) { Destroy(chunkData.instance); Addressables.Release(chunkData.handle); _loadedChunks.Remove(location); } } // 场景销毁时清理所有资源 private void OnDestroy() { foreach (var chunk in _loadedChunks.Values) { Destroy(chunk.instance); Addressables.Release(chunk.handle); } _loadedChunks.Clear(); } }
额外注意事项
- 区块拆分:将2GB的地图拆分为更小的独立区块(比如按100x100地形单位划分),降低单次加载的内存压力。
- 内存监控:用Unity Profiler的Memory模块实时追踪内存变化,确认资源是否被正确释放。
- 资源分组:把同区域的地图区块归到同一个Addressable组,可优化加载效率。
- 错误处理:所有异步操作都要检查
Status,避免失败操作残留无效引用。
内容的提问来源于stack exchange,提问作者marietta
相关产品推荐
相关产品推荐

