Files
YooAsset/Assets/YooAsset/Runtime/ResourceManager
2026-01-16 14:37:04 +08:00
..
2026-01-16 10:28:01 +08:00
2026-01-16 14:37:04 +08:00
2026-01-16 10:28:01 +08:00
2026-01-16 14:37:04 +08:00
2026-01-06 17:12:07 +08:00
2026-01-16 10:28:01 +08:00

ResourceManager 资源管理器

模块概述

ResourceManager 是 YooAsset 资源管理系统的核心执行层,负责资源加载的实际执行和生命周期管理。该模块通过 Provider 模式实现资源加载抽象,通过 Handle 模式提供面向用户的类型安全访问接口。

核心特性

  • Provider 抽象:统一的资源加载操作模式,支持复用机制
  • Handle 封装:类型安全的用户访问接口,支持协程和 async/await
  • 引用计数:精确的资源生命周期追踪,自动卸载未使用资源
  • 并发控制:可配置的 Bundle 加载并发限制,避免系统过载

模块统计

子模块 职责
核心 ResourceManager + DownloadStatus
Handle 系统 面向用户的资源句柄
Provider 系统 资源加载执行器
Operation 系统 异步操作集合
总计 完整资源管理系统

设计目标

目标 说明
统一加载接口 通过 Provider 模式抽象不同类型资源的加载逻辑
类型安全访问 Handle 模式封装资源访问,提供编译时类型检查
资源生命周期 引用计数精确追踪,支持自动和手动卸载
并发流量控制 可配置的 Bundle 加载并发数,平衡性能与稳定性
Provider 复用 相同资源的多次加载共享同一个 Provider

文件结构

ResourceManager/
├── ResourceManager.cs              # 主管理类
├── DownloadStatus.cs               # 下载状态结构体
├── Handle/                         # 句柄系统
│   ├── HandleBase.cs              # 句柄基类
│   ├── HandleFactory.cs           # 句柄工厂
│   ├── AssetHandle.cs             # 资源句柄
│   ├── SceneHandle.cs             # 场景句柄
│   ├── SubAssetsHandle.cs         # 子资源句柄
│   ├── AllAssetsHandle.cs         # 全部资源句柄
│   └── RawFileHandle.cs           # 原生文件句柄
├── Provider/                       # 提供者系统
│   ├── ProviderOperation.cs       # 提供者基类
│   ├── AssetProvider.cs           # 资源提供者
│   ├── SceneProvider.cs           # 场景提供者
│   ├── SubAssetsProvider.cs       # 子资源提供者
│   ├── AllAssetsProvider.cs       # 全部资源提供者
│   ├── RawFileProvider.cs         # 原生文件提供者
│   └── CompletedProvider.cs       # 完成提供者(错误快速返回)
└── Operation/                      # 操作系统
    ├── Internal/
    │   └── LoadBundleFileOperation.cs  # Bundle 加载操作
    ├── InstantiateOperation.cs         # 实例化操作
    ├── UnloadSceneOperation.cs         # 场景卸载操作
    ├── UnloadAllAssetsOperation.cs     # 全部资源卸载操作
    └── UnloadUnusedAssetsOperation.cs  # 未使用资源卸载操作

核心类说明

ResourceManager

资源管理器主类,作为资源加载操作的中央枢纽。

internal class ResourceManager
{
    // 核心数据结构
    internal readonly Dictionary<string, ProviderOperation> ProviderDic;    // 容量 5000
    internal readonly Dictionary<string, LoadBundleFileOperation> LoaderDic; // 容量 5000
    internal readonly List<SceneHandle> SceneHandles;                        // 容量 100

    // 配置属性
    public bool AutoUnloadBundleWhenUnused { get; }      // 自动卸载未使用的 Bundle
    public bool WebGLForceSyncLoadAsset { get; }         // WebGL 强制同步加载
    public bool LockLoadOperation { get; set; }          // 加载操作锁定
    public int BundleLoadingMaxConcurrency { get; }      // Bundle 并发加载数量 (默认32范围1-256)
    public int BundleLoadingCounter { get; set; }        // 正在加载的 Bundle 计数
}

初始化和销毁

public void Initialize(InitializeParameters parameters, IBundleQuery bundleServices)
{
    _bundleLoadingMaxConcurrency = parameters.BundleLoadingMaxConcurrency;
    AutoUnloadBundleWhenUnused = parameters.AutoUnloadBundleWhenUnused;
    WebGLForceSyncLoadAsset = parameters.WebGLForceSyncLoadAsset;
    _bundleQuery = bundleServices;
    SceneManager.sceneUnloaded += OnSceneUnloaded;
}

public void Destroy()
{
    SceneManager.sceneUnloaded -= OnSceneUnloaded;
}

核心加载 API

方法 返回类型 说明
LoadAssetAsync() AssetHandle 加载单个资源
LoadSceneAsync() SceneHandle 加载场景
LoadSubAssetsAsync() SubAssetsHandle 加载子资源
LoadAllAssetsAsync() AllAssetsHandle 加载所有资源
LoadRawFileAsync() RawFileHandle 加载原生文件

Bundle 加载器管理

// 创建主 Bundle 加载器
internal LoadBundleFileOperation CreateMainBundleFileLoader(AssetInfo assetInfo)

// 创建依赖 Bundle 加载器列表
internal List<LoadBundleFileOperation> CreateDependBundleFileLoaders(AssetInfo assetInfo)

// 检查是否繁忙
public bool BundleLoadingIsBusy()
{
    return BundleLoadingCounter >= _bundleLoadingMaxConcurrency;
}

DownloadStatus

下载状态结构体,用于追踪资源下载进度。

public struct DownloadStatus
{
    public long DownloadedBytes;  // 已下载字节数
    public long TotalBytes;       // 总字节数
    public float Progress;        // 下载进度 (0-1)

    public static DownloadStatus CreateDefaultStatus()
    {
        return new DownloadStatus
        {
            DownloadedBytes = 0,
            TotalBytes = 0,
            Progress = 1f
        };
    }
}

Provider 系统

Provider 系统负责资源加载的实际执行,每种资源类型都有对应的 Provider 实现。

ProviderOperation基类

所有资源提供者的抽象基类,继承自 AsyncOperationBase

状态机

None → StartBundleLoader → WaitBundleLoader → ProcessBundleResult → Done
protected enum ESteps
{
    None = 0,
    StartBundleLoader,      // 启动所有 Bundle 加载器
    WaitBundleLoader,       // 等待 Bundle 加载完成
    ProcessBundleResult,    // 处理 Bundle 结果(子类实现)
    Done,                   // 完成
}

核心属性

public abstract class ProviderOperation : AsyncOperationBase
{
    public string ProviderGUID { get; }                      // 唯一标识符
    public AssetInfo MainAssetInfo { get; }                  // 资源信息
    public UnityEngine.Object AssetObject { get; }           // 单个资源对象
    public UnityEngine.Object[] AllAssetObjects { get; }     // 全部资源对象数组
    public UnityEngine.Object[] SubAssetObjects { get; }     // 子资源对象数组
    public Scene SceneObject { get; }                        // 场景对象
    public BundleResult BundleResultObject { get; }          // Bundle 结果
    public int RefCount { get; }                             // 引用计数
    public bool IsDestroyed { get; }                         // 销毁标志
    public string SceneName { get; }                         // 场景名称
}

引用计数管理

// 创建句柄(引用计数 +1
public T CreateHandle<T>() where T : HandleBase
{
    RefCount++;
    HandleBase handle = HandleFactory.CreateHandle(this, typeof(T));
    _handles.Add(handle);
    return handle as T;
}

// 释放句柄(引用计数 -1
public void ReleaseHandle(HandleBase handle)
{
    if (RefCount <= 0)
        throw new YooInternalException(...);

    if (_handles.Remove(handle) == false)
        throw new YooInternalException(...);

    RefCount--;
}

// 检查是否可销毁
public bool CanDestroyProvider()
{
    // 注意:正在加载中的任务不可以销毁
    if (IsLoading) return false;
    return RefCount <= 0;
}

核心执行流程

internal override void InternalUpdate()
{
    if (_steps == ESteps.StartBundleLoader)
    {
        // 启动主 Bundle 加载器和所有依赖 Bundle 加载器
        foreach (var bundleLoader in _bundleLoaders)
        {
            bundleLoader.StartOperation();
            AddChildOperation(bundleLoader);
        }
        _steps = ESteps.WaitBundleLoader;
    }

    if (_steps == ESteps.WaitBundleLoader)
    {
        // 等待所有 Bundle 加载完成并验证成功
        foreach (var bundleLoader in _bundleLoaders)
        {
            if (bundleLoader.IsDone == false) return;
            if (bundleLoader.Status != EOperationStatus.Succeed)
            {
                InvokeCompletion(error, EOperationStatus.Failed);
                return;
            }
        }
        _steps = ESteps.ProcessBundleResult;
    }

    if (_steps == ESteps.ProcessBundleResult)
    {
        // 子类实现的核心加载逻辑
        ProcessBundleResult();
    }
}

Provider 子类

类型 职责 结果属性 说明
AssetProvider 加载单个资源 AssetObject 最常用的加载方式
SceneProvider 加载场景 SceneObject 支持挂起加载
SubAssetsProvider 加载子资源 SubAssetObjects 用于图集、精灵等
AllAssetsProvider 加载所有资源 AllAssetObjects 加载 Bundle 内所有资源
RawFileProvider 加载原生文件 BundleResultObject 配置文件、二进制数据等
CompletedProvider 错误快速返回 - 用于无效请求的快速失败

AssetProvider 示例

internal class AssetProvider : ProviderOperation
{
    private FSLoadAssetOperation _loadAssetOp;

    protected override void ProcessBundleResult()
    {
        if (_loadAssetOp == null)
        {
            _loadAssetOp = BundleResultObject.LoadAssetAsync(MainAssetInfo);
            _loadAssetOp.StartOperation();
            AddChildOperation(_loadAssetOp);

#if UNITY_WEBGL
            if (_resManager.WebGLForceSyncLoadAsset)
                _loadAssetOp.WaitForAsyncComplete();
#endif
        }

        _loadAssetOp.UpdateOperation();
        Progress = _loadAssetOp.Progress;

        if (_loadAssetOp.IsDone == false) return;

        if (_loadAssetOp.Status != EOperationStatus.Succeed)
            InvokeCompletion(_loadAssetOp.Error, EOperationStatus.Failed);
        else
        {
            AssetObject = _loadAssetOp.Result;
            InvokeCompletion(string.Empty, EOperationStatus.Succeed);
        }
    }
}

SceneProvider 示例

internal class SceneProvider : ProviderOperation
{
    private LoadSceneParameters _loadParams;
    private bool _suspendLoad;

    public SceneProvider(ResourceManager manager, string providerGUID, AssetInfo assetInfo,
                         LoadSceneParameters loadParams, bool suspendLoad)
        : base(manager, providerGUID, assetInfo)
    {
        _loadParams = loadParams;
        _suspendLoad = suspendLoad;
        SceneName = Path.GetFileNameWithoutExtension(assetInfo.AssetPath);
    }

    // 取消挂起加载
    public void UnSuspendLoad()
    {
        _suspendLoad = false;
    }

    protected override void ProcessBundleResult()
    {
        if (_loadSceneOp == null)
        {
            _loadSceneOp = BundleResultObject.LoadSceneOperation(
                MainAssetInfo, _loadParams, _suspendLoad);
            _loadSceneOp.StartOperation();
            AddChildOperation(_loadSceneOp);
        }

        // 支持中途取消挂起
        if (_suspendLoad == false)
            _loadSceneOp.UnSuspendLoad();

        // ... 进度更新和完成处理
    }
}

Handle 系统

Handle 系统提供面向用户的资源访问接口,通过代理模式封装 Provider。

HandleBase基类

所有句柄的抽象基类,实现 IEnumeratorIDisposable 接口。

public abstract class HandleBase : IEnumerator, IDisposable
{
    private readonly AssetInfo _assetInfo;
    internal ProviderOperation Provider { get; private set; }

    // 有效性检查
    public bool IsValid
    {
        get { return Provider != null && Provider.IsDestroyed == false; }
    }

    // 释放句柄
    public void Release()
    {
        if (IsValidWithWarning == false) return;
        Provider.ReleaseHandle(this);

        // 主动卸载零引用的资源包
        if (Provider.RefCount == 0)
            Provider.TryUnloadBundle();

        Provider = null;
    }

    // IDisposable 实现
    public void Dispose()
    {
        this.Release();
    }
}

代理 Provider 属性

public EOperationStatus Status
{
    get { return IsValidWithWarning ? Provider.Status : EOperationStatus.None; }
}

public string LastError
{
    get { return IsValidWithWarning ? Provider.Error : string.Empty; }
}

public float Progress
{
    get { return IsValidWithWarning ? Provider.Progress : 0; }
}

public bool IsDone
{
    get { return IsValidWithWarning ? Provider.IsDone : true; }
}

public Task Task
{
    get { return IsValidWithWarning ? Provider.Task : null; }
}

协程支持

bool IEnumerator.MoveNext()
{
    return !IsDone;  // 返回 false 时循环结束
}

void IEnumerator.Reset() { }

object IEnumerator.Current
{
    get { return Provider; }
}

具体 Handle 类型

AssetHandle

资源句柄,用于访问加载的单个资源。

public sealed class AssetHandle : HandleBase
{
    private System.Action<AssetHandle> _callback;

    // 完成事件
    public event System.Action<AssetHandle> Completed
    {
        add
        {
            if (IsValidWithWarning == false)
                throw new YooHandleException(...);
            if (Provider.IsDone)
                value.Invoke(this);  // 已完成则立即调用
            else
                _callback += value;  // 未完成则等待
        }
        remove { _callback -= value; }
    }

    // 资源对象访问
    public UnityEngine.Object AssetObject
    {
        get { return IsValidWithWarning ? Provider.AssetObject : null; }
    }

    public TAsset GetAssetObject<TAsset>() where TAsset : UnityEngine.Object
    {
        return IsValidWithWarning ? Provider.AssetObject as TAsset : null;
    }

    // 实例化支持
    public GameObject InstantiateSync();
    public GameObject InstantiateSync(Transform parent);
    public GameObject InstantiateSync(Transform parent, bool worldPositionStays);
    public GameObject InstantiateSync(Vector3 position, Quaternion rotation);
    public GameObject InstantiateSync(Vector3 position, Quaternion rotation, Transform parent);

    public InstantiateOperation InstantiateAsync();
    public InstantiateOperation InstantiateAsync(Transform parent);
    public InstantiateOperation InstantiateAsync(Transform parent, bool worldPositionStays);
    public InstantiateOperation InstantiateAsync(Vector3 position, Quaternion rotation);
    public InstantiateOperation InstantiateAsync(Vector3 position, Quaternion rotation, Transform parent);
}

SceneHandle

场景句柄,用于管理加载的场景。

public class SceneHandle : HandleBase
{
    internal string PackageName { get; set; }

    // 场景名称
    public string SceneName
    {
        get { return IsValidWithWarning ? Provider.SceneName : string.Empty; }
    }

    // 场景对象
    public Scene SceneObject
    {
        get { return IsValidWithWarning ? Provider.SceneObject : new Scene(); }
    }

    // 激活场景
    public bool ActivateScene()
    {
        if (IsValidWithWarning == false) return false;
        if (SceneObject.IsValid() && SceneObject.isLoaded)
            return SceneManager.SetActiveScene(SceneObject);
        return false;
    }

    // 取消挂起加载
    public bool UnSuspend()
    {
        if (IsValidWithWarning == false) return false;
        if (Provider is SceneProvider provider)
            provider.UnSuspendLoad();
        return true;
    }

    // 卸载场景
    public UnloadSceneOperation UnloadAsync()
    {
        if (IsValidWithWarning == false)
        {
            var operation = new UnloadSceneOperation(error);
            OperationSystem.StartOperation(packageName, operation);
            return operation;
        }

        var op = new UnloadSceneOperation(Provider);
        OperationSystem.StartOperation(packageName, op);
        return op;
    }
}

SubAssetsHandle

子资源句柄,用于访问 Bundle 内的子资源(如图集中的精灵)。

public sealed class SubAssetsHandle : HandleBase
{
    // 所有子资源
    public IReadOnlyList<UnityEngine.Object> SubAssetObjects
    {
        get { return IsValidWithWarning ? Provider.SubAssetObjects : null; }
    }

    // 获取指定名称的子资源
    public TObject GetSubAssetObject<TObject>(string assetName)
        where TObject : UnityEngine.Object
    {
        if (IsValidWithWarning == false) return null;

        foreach (var assetObject in Provider.SubAssetObjects)
        {
            if (assetObject.name == assetName && assetObject is TObject)
                return assetObject as TObject;
        }

        YooLogger.Warning($"Not found sub asset object : {assetName}");
        return null;
    }

    // 获取所有指定类型的子资源
    public TObject[] GetSubAssetObjects<TObject>()
        where TObject : UnityEngine.Object
    {
        if (IsValidWithWarning == false) return null;

        List<TObject> result = new List<TObject>(Provider.SubAssetObjects.Length);
        foreach (var assetObject in Provider.SubAssetObjects)
        {
            var retObject = assetObject as TObject;
            if (retObject != null)
                result.Add(retObject);
        }
        return result.ToArray();
    }
}

AllAssetsHandle

全部资源句柄,用于访问 Bundle 内的所有资源。

public sealed class AllAssetsHandle : HandleBase
{
    public IReadOnlyList<UnityEngine.Object> AllAssetObjects
    {
        get { return IsValidWithWarning ? Provider.AllAssetObjects : null; }
    }
}

RawFileHandle

原生文件句柄,用于访问未经 Unity 处理的原始文件。

public class RawFileHandle : HandleBase
{
    // 读取二进制数据
    public byte[] GetRawFileData()
    {
        if (IsValidWithWarning == false) return null;
        return Provider.BundleResultObject.ReadBundleFileData();
    }

    // 读取文本内容
    public string GetRawFileText()
    {
        if (IsValidWithWarning == false) return null;
        return Provider.BundleResultObject.ReadBundleFileText();
    }

    // 获取文件路径
    public string GetRawFilePath()
    {
        if (IsValidWithWarning == false) return string.Empty;
        return Provider.BundleResultObject.GetBundleFilePath();
    }
}

HandleFactory

句柄工厂,使用字典映射类型到构造函数。

internal static class HandleFactory
{
    private static readonly Dictionary<Type, Func<ProviderOperation, HandleBase>>
        _handleFactory = new Dictionary<Type, Func<ProviderOperation, HandleBase>>()
    {
        { typeof(AssetHandle), op => new AssetHandle(op) },
        { typeof(SceneHandle), op => new SceneHandle(op) },
        { typeof(SubAssetsHandle), op => new SubAssetsHandle(op) },
        { typeof(AllAssetsHandle), op => new AllAssetsHandle(op) },
        { typeof(RawFileHandle), op => new RawFileHandle(op) }
    };

    public static HandleBase CreateHandle(ProviderOperation operation, Type type)
    {
        if (_handleFactory.TryGetValue(type, out var factory) == false)
            throw new NotImplementedException($"Handle type {type.FullName} is not supported.");
        return factory(operation);
    }
}

Loader 系统

LoadBundleFileOperation

Bundle 文件加载操作,负责 Bundle 的实际加载和并发控制。

状态机

None → CheckConcurrency → LoadBundleFile → Done
private enum ESteps
{
    None,
    CheckConcurrency,   // 检查并发限制
    LoadBundleFile,     // 执行 Bundle 加载
    Done,
}

核心属性

internal class LoadBundleFileOperation : AsyncOperationBase
{
    public BundleInfo LoadBundleInfo { get; }      // Bundle 信息
    public BundleResult Result { get; set; }       // 加载结果
    public int RefCount { get; }                   // 引用计数
    public long DownloadedBytes { get; set; }      // 已下载字节数
    public float DownloadProgress { get; set; }    // 下载进度
    public bool IsDestroyed { get; }               // 销毁标志
}

并发控制流程

internal override void InternalUpdate()
{
    if (_steps == ESteps.CheckConcurrency)
    {
        // 检查是否超过最大并发加载数
        if (_resManager.BundleLoadingIsBusy())
            return;  // 等待直到有空闲位置

        _steps = ESteps.LoadBundleFile;
    }

    if (_steps == ESteps.LoadBundleFile)
    {
        if (_loadBundleOp == null)
        {
            // 统计计数增加
            _resManager.BundleLoadingCounter++;
            _loadBundleOp = LoadBundleInfo.LoadBundleFile();
            _loadBundleOp.StartOperation();
            AddChildOperation(_loadBundleOp);
        }

        // ... 等待加载完成 ...

        // 统计计数减少
        _resManager.BundleLoadingCounter--;
    }
}

引用计数管理

public void Reference()
{
    RefCount++;
}

public void Release()
{
    RefCount--;
}

public bool CanDestroyLoader()
{
    if (CanReleasableLoader() == false)
        return false;

    // 检查引用链上的资源包是否已经全部销毁
    // 注意:互相引用的资源包无法卸载!
    if (LoadBundleInfo.Bundle.ReferenceBundleIDs.Count > 0)
    {
        foreach (var bundleID in LoadBundleInfo.Bundle.ReferenceBundleIDs)
        {
#if YOOASSET_EXPERIMENTAL
            if (_resManager.CheckBundleReleasable(bundleID) == false)
                return false;
#else
            if (_resManager.CheckBundleDestroyed(bundleID) == false)
                return false;
#endif
        }
    }

    return true;
}

Provider 管理

private readonly List<ProviderOperation> _providers = new List<ProviderOperation>(100);

public void AddProvider(ProviderOperation provider)
{
    if (_providers.Contains(provider) == false)
        _providers.Add(provider);
}

public void TryDestroyProviders()
{
    // 获取可销毁的 Provider 列表
    _removeList.Clear();
    foreach (var provider in _providers)
    {
        if (provider.CanDestroyProvider())
            _removeList.Add(provider);
    }

    // 销毁 Provider
    foreach (var provider in _removeList)
    {
        _providers.Remove(provider);
        provider.DestroyProvider();
    }

    // 从 ResourceManager 中移除
    if (_removeList.Count > 0)
    {
        _resManager.RemoveBundleProviders(_removeList);
        _removeList.Clear();
    }
}

操作类系统

InstantiateOperation

实例化操作,支持同步和异步实例化 GameObject。

public class InstantiateOperation : AsyncOperationBase
{
    public GameObject Result { get; private set; }

    // 支持的实例化参数
    private Transform _parent;
    private bool _worldPositionStays;
    private Vector3 _position;
    private Quaternion _rotation;
    private bool _setPositionAndRotation;
}

UnloadSceneOperation

场景卸载操作。

public class UnloadSceneOperation : AsyncOperationBase
{
    // 状态流程UnloadScene → Done
    private enum ESteps
    {
        None,
        UnloadScene,
        Done,
    }
}

UnloadAllAssetsOperation

卸载包裹内所有资源操作。

public class UnloadAllAssetsOperation : AsyncOperationBase
{
    // 状态流程CheckInit → ClearProvider → ClearLoader → Done
    private enum ESteps
    {
        None,
        CheckInit,
        ClearProvider,
        ClearLoader,
        Done,
    }
}

UnloadUnusedAssetsOperation

卸载未使用资源操作,支持迭代清理。

public class UnloadUnusedAssetsOperation : AsyncOperationBase
{
    private int _maxIterationCount;  // 最大迭代次数

    // 每次迭代清理一轮未使用的资源
    // 复杂的依赖链可能需要多次迭代
}

关键工作流

资源加载流程

用户请求 LoadAssetAsync(location)
    ↓
ResourcePackage 转换 → AssetInfo
    ↓
ResourceManager.LoadAssetAsync(assetInfo)
    ├─ 构造 ProviderGUID (LoadAssetAsync + AssetInfo.GUID)
    ├─ 查找已有 Provider (ProviderDic.TryGetValue)
    ├─ 创建新 Provider (如不存在)
    │   ├─ new AssetProvider(...)
    │   ├─ 创建 LoadBundleFileOperation (主 Bundle)
    │   └─ 创建 LoadBundleFileOperation[] (依赖 Bundle)
    ├─ 注册到 ProviderDic
    ├─ 启动 OperationSystem
    └─ 返回 Handle (provider.CreateHandle<AssetHandle>())
    ↓
ProviderOperation.InternalUpdate()
    ├─ StartBundleLoader启动所有 Bundle 加载器
    ├─ WaitBundleLoader等待 Bundle 加载完成
    └─ ProcessBundleResult调用 BundleResult.LoadAssetAsync()
    ↓
LoadBundleFileOperation.InternalUpdate()
    ├─ CheckConcurrency检查并发限制
    ├─ LoadBundleFile调用 IFileSystem.LoadBundleFile()
    └─ 返回 BundleResult
    ↓
用户获得 Handle
    ├─ await handle.ToTask()
    ├─ yield return handle
    └─ handle.AssetObject

资源卸载流程

用户释放 handle.Release()
    ↓
HandleBase.Release()
    ├─ Provider.ReleaseHandle(this)
    ├─ RefCount--
    └─ 如果 RefCount == 0Provider.TryUnloadBundle()
    ↓
ProviderOperation.TryUnloadBundle()
    └─ 如果 AutoUnloadBundleWhenUnused
        ResourceManager.TryUnloadUnusedAsset(assetInfo, loopCount)
    ↓
ResourceManager.TryUnloadUnusedAsset()
    ├─ 循环处理依赖链 (loopCount 次)
    ├─ 卸载主 Bundle
    │   ├─ TryDestroyProviders()
    │   ├─ CanDestroyLoader() 检查
    │   └─ DestroyLoader()
    └─ 卸载依赖 Bundle
        ├─ CanDestroyLoader() 检查
        └─ DestroyLoader()
    ↓
LoadBundleFileOperation.DestroyLoader()
    └─ BundleResult.UnloadBundleFile()

Provider 复用机制

多次加载同一资源:
    LoadAssetAsync("Player.prefab") → Provider A (新建)
    LoadAssetAsync("Player.prefab") → Provider A (复用)
    LoadAssetAsync("Player.prefab") → Provider A (复用)

ProviderGUID 构造规则:
    ProviderGUID = MethodName + AssetInfo.GUID
    例如LoadAssetAsync + abc123def456 → "LoadAssetAsyncabc123def456"

复用条件:
    if (ProviderDic.TryGetValue(providerGUID, out provider))
        return provider.CreateHandle<T>();  // 复用现有 Provider

每次复用:
    RefCount++ (通过 CreateHandle)

类继承关系图

AsyncOperationBase
├── ProviderOperation (资源提供者基类)
│   ├── AssetProvider         (加载单个资源)
│   ├── SceneProvider         (加载场景)
│   ├── SubAssetsProvider     (加载子资源)
│   ├── AllAssetsProvider     (加载所有资源)
│   ├── RawFileProvider       (加载原生文件)
│   └── CompletedProvider     (错误快速返回)
├── LoadBundleFileOperation   (Bundle 加载)
├── InstantiateOperation      (实例化)
├── UnloadSceneOperation      (场景卸载)
├── UnloadAllAssetsOperation  (全部卸载)
└── UnloadUnusedAssetsOperation (未使用卸载)

HandleBase (IEnumerator, IDisposable)
├── AssetHandle      (资源句柄)
├── SceneHandle      (场景句柄)
├── SubAssetsHandle  (子资源句柄)
├── AllAssetsHandle  (全部资源句柄)
└── RawFileHandle    (原生文件句柄)

与其他模块的交互

ResourcePackage
    │
    ├─ 持有 → ResourceManager 实例
    │           ├─ LoadAssetAsync()
    │           ├─ LoadSceneAsync()
    │           ├─ LoadSubAssetsAsync()
    │           ├─ LoadAllAssetsAsync()
    │           └─ LoadRawFileAsync()
    │
    └─ 实现 → IBundleQuery 接口
                ├─ GetMainBundleInfo(AssetInfo) → BundleInfo
                ├─ GetDependBundleInfos(AssetInfo) → List<BundleInfo>
                └─ GetMainBundleName(bundleID) → string

ResourceManager
    │
    ├─ 依赖 → IBundleQuery (Bundle 查询)
    │
    ├─ 使用 → BundleInfo
    │           └─ LoadBundleFile() → FSLoadBundleOperation
    │
    └─ 间接使用 → IFileSystem
                    └─ 通过 BundleInfo 调用
                        ├─ LoadBundleFile(Bundle)
                        └─ 返回 FSLoadBundleOperation

并发流量控制

ResourceManager 维护的限制:
├─ BundleLoadingMaxConcurrency (默认 32范围 1-256)
│   └─ 限制同时加载的 Bundle 文件数量
├─ BundleLoadingCounter (当前计数)
│   └─ 由 LoadBundleFileOperation 增减
└─ BundleLoadingIsBusy() 检查
    └─ 超过限制则阻塞新的 Bundle 加载

FileSystem (Cache) 维护的限制:
├─ FileVerifyMaxConcurrency (默认 32范围 1-256)
│   └─ 限制同时验证的文件数量
├─ DownloadMaxConcurrency (默认 10范围 1-64)
│   └─ 限制同时下载的文件数量
└─ DownloadMaxRequestPerFrame (默认 5范围 1-20)
    └─ 限制每帧发起的下载请求数

使用示例

加载资源

// 异步加载async/await
var handle = package.LoadAssetAsync<GameObject>("Assets/Prefabs/Player.prefab");
await handle.ToTask();
var prefab = handle.GetAssetObject<GameObject>();

// 使用资源
var instance = GameObject.Instantiate(prefab);

// 释放资源(必须!)
handle.Release();
// 异步加载(协程)
var handle = package.LoadAssetAsync<GameObject>("Assets/Prefabs/Player.prefab");
yield return handle;
var prefab = handle.GetAssetObject<GameObject>();

// 使用资源
var instance = GameObject.Instantiate(prefab);

// 释放资源
handle.Release();
// 异步加载(回调)
var handle = package.LoadAssetAsync<GameObject>("Assets/Prefabs/Player.prefab");
handle.Completed += (h) =>
{
    var prefab = h.GetAssetObject<GameObject>();
    var instance = GameObject.Instantiate(prefab);

    // 注意:回调中也需要释放
    h.Release();
};

加载场景

// 加载场景(支持挂起)
var sceneHandle = package.LoadSceneAsync("Assets/Scenes/Main.unity",
    LoadSceneMode.Additive, suspendLoad: true);

// 在适当时机取消挂起
sceneHandle.UnSuspend();

await sceneHandle.ToTask();

// 激活场景
sceneHandle.ActivateScene();

// 卸载场景
var unloadOp = sceneHandle.UnloadAsync();
await unloadOp.ToTask();

加载子资源

// 加载图集
var handle = package.LoadSubAssetsAsync<Sprite>("Assets/Atlas/UI.spriteatlas");
await handle.ToTask();

// 获取特定精灵
var homeIcon = handle.GetSubAssetObject<Sprite>("icon_home");
var settingsIcon = handle.GetSubAssetObject<Sprite>("icon_settings");

// 获取所有精灵
var allSprites = handle.GetSubAssetObjects<Sprite>();

// 释放资源
handle.Release();

加载原生文件

// 加载 JSON 配置
var handle = package.LoadRawFileAsync("Assets/Config/settings.json");
await handle.ToTask();

// 读取文本
string json = handle.GetRawFileText();
var settings = JsonUtility.FromJson<Settings>(json);

// 释放资源
handle.Release();
// 加载二进制文件
var handle = package.LoadRawFileAsync("Assets/Data/binary.bytes");
await handle.ToTask();

// 读取二进制数据
byte[] data = handle.GetRawFileData();

// 或获取文件路径(用于第三方库)
string path = handle.GetRawFilePath();

handle.Release();

实例化操作

var handle = package.LoadAssetAsync<GameObject>("Assets/Prefabs/Player.prefab");
await handle.ToTask();

// 同步实例化
var go1 = handle.InstantiateSync();
var go2 = handle.InstantiateSync(parentTransform);
var go3 = handle.InstantiateSync(parentTransform, worldPositionStays: false);
var go4 = handle.InstantiateSync(position, rotation);
var go5 = handle.InstantiateSync(position, rotation, parentTransform);

// 异步实例化
var instOp = handle.InstantiateAsync(parentTransform);
await instOp.ToTask();
var go6 = instOp.Result;

// 释放资源
handle.Release();

使用 using 语句自动释放

// 利用 IDisposable 接口
using (var handle = package.LoadAssetAsync<GameObject>("Assets/Prefabs/Player.prefab"))
{
    await handle.ToTask();
    var prefab = handle.GetAssetObject<GameObject>();
    var instance = GameObject.Instantiate(prefab);
}
// using 块结束时自动调用 handle.Dispose() → Release()

注意事项

  1. 必须释放 Handle

    • 使用后必须调用 handle.Release() 避免内存泄漏
    • 可以使用 using 语句自动释放
  2. Provider 复用

    • 相同资源的多次加载会复用同一个 Provider
    • 每次加载都会增加引用计数
  3. 并发限制

    • Bundle 加载最大并发数为 256默认 32
    • 超过限制的加载请求会排队等待
  4. 引用计数

    • RefCount 为 0 且 AutoUnloadBundleWhenUnused 为 true 时自动卸载
    • 复杂依赖链可能需要多次迭代才能完全卸载
  5. WebGL 特殊处理

    • 可配置 WebGLForceSyncLoadAsset 强制同步加载
    • WebGL 平台不支持多线程
  6. 循环依赖

    • 通过 YOOASSET_EXPERIMENTAL 宏处理循环 Bundle 依赖
    • 实验性功能,需谨慎使用
  7. 线程安全

    • 所有资源管理逻辑在主线程执行
    • 多线程仅用于下载和文件验证
  8. 场景加载

    • 场景不支持 Provider 复用
    • 每次加载都会创建新的 Provider使用递增的 sceneCreateIndex

性能优化建议

  1. 合理设置并发数

    • 根据设备性能调整 BundleLoadingMaxConcurrency
    • 移动设备建议 16-32PC 可设置更高
  2. 预加载常用资源

    • 提前加载常用资源并持有 Handle
    • 避免运行时频繁加载/卸载
  3. 批量加载

    • 使用 LoadAllAssetsAsync 加载 Bundle 内所有资源
    • 减少多次加载请求的开销
  4. 及时释放

    • 不再使用的资源及时调用 Release()
    • 避免内存占用过高
  5. 使用资源标签

    • 合理规划资源标签
    • 利用标签进行批量下载和加载