Unity AssetBundle 管理与加载流程详解

一、AssetBundle 基本概念

1.1 什么是 AssetBundle

AssetBundle 是 Unity 提供的资源打包系统,可以将游戏资源(模型、纹理、音频、预制体等)打包成独立的文件,用于:

  • 资源热更新

  • 按需加载(减少初始包体大小)

  • DLC 内容分发

  • 平台适配(不同平台使用不同资源)

1.2 AssetBundle 结构

text

AssetBundle 文件
├── 资源数据(序列化数据)
├── 资源头信息
├── 资源依赖信息
└── 文件清单(Manifest)

二、AssetBundle 完整工作流程

2.1 创建与打包流程

csharp

// 1. 标记资源 AssetBundle 标签
// 在 Editor 中为资源设置 AssetBundle 名称和变体

// 2. 构建 AssetBundle
using UnityEditor;
using System.IO;

public class AssetBundleBuilder
{
    [MenuItem("Tools/Build AssetBundles")]
    static void BuildAllAssetBundles()
    {
        string outputPath = "Assets/AssetBundles";
        
        if (!Directory.Exists(outputPath))
            Directory.CreateDirectory(outputPath);
        
        // 构建选项
        BuildAssetBundleOptions options = 
            BuildAssetBundleOptions.ChunkBasedCompression |  // LZ4压缩
            BuildAssetBundleOptions.DeterministicAssetBundle; // 确定性构建
        
        // 构建平台
        BuildTarget target = BuildTarget.StandaloneWindows;
        
        // 执行构建
        BuildPipeline.BuildAssetBundles(
            outputPath, 
            options, 
            target
        );
        
        Debug.Log("AssetBundles 构建完成!");
    }
}

2.2 加载流程架构

csharp

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;

/// <summary>
/// AssetBundle 加载模式
/// </summary>
public enum BundleLoadMode
{
    Local,      // 本地加载
    Remote,     // 远程加载
    Persistent  // 持久化目录加载
}

/// <summary>
/// AssetBundle 加载优先级
/// </summary>
public enum BundleLoadPriority
{
    Low = 0,
    Normal = 1,
    High = 2,
    Immediate = 3  // 同步加载,只在必要时使用
}

/// <summary>
/// AssetBundle 加载状态
/// </summary>
public enum BundleLoadState
{
    NotLoaded,
    Loading,
    Loaded,
    Failed
}

/// <summary>
/// AssetBundle 引用信息
/// </summary>
[System.Serializable]
public class BundleReferenceInfo
{
    public string bundleName;
    public int referenceCount;           // 引用计数
    public DateTime lastAccessTime;     // 最后访问时间
    public long bundleSize;             // Bundle大小(字节)
    public bool isPersistent;           // 是否常驻内存
    public List<string> dependentBundles; // 依赖此Bundle的其他Bundle
    
    public BundleReferenceInfo(string name)
    {
        bundleName = name;
        referenceCount = 0;
        lastAccessTime = DateTime.Now;
        dependentBundles = new List<string>();
    }
}

/// <summary>
/// 完善的 AssetBundle 管理器
/// </summary>
public class AssetBundleManager : MonoBehaviour
{
    #region 单例模式
    private static AssetBundleManager _instance;
    public static AssetBundleManager Instance
    {
        get
        {
            if (_instance == null)
            {
                GameObject go = new GameObject("AssetBundleManager");
                _instance = go.AddComponent<AssetBundleManager>();
                DontDestroyOnLoad(go);
            }
            return _instance;
        }
    }
    #endregion

    #region 配置参数
    [Header("配置参数")]
    [SerializeField] private bool enableLog = true;
    [SerializeField] private bool enableProfiling = true;
    [SerializeField] private int maxConcurrentLoads = 3;           // 最大并发加载数
    [SerializeField] private float unloadUnusedDelay = 60f;       // 清理未使用资源延迟(秒)
    [SerializeField] private long memoryThreshold = 100 * 1024 * 1024; // 内存阈值(100MB)
    [SerializeField] private int maxCacheBundles = 20;            // 最大缓存Bundle数量
    
    [Header("路径配置")]
    [SerializeField] private string remoteBundleUrl = "http://your-server.com/assetbundles/";
    [SerializeField] private string localBundlePath = "AssetBundles";
    #endregion

    #region 内部数据结构
    // 已加载的AssetBundle缓存
    private Dictionary<string, AssetBundle> loadedBundles = new Dictionary<string, AssetBundle>();
    
    // Bundle引用信息
    private Dictionary<string, BundleReferenceInfo> bundleReferences = new Dictionary<string, BundleReferenceInfo>();
    
    // 正在加载的Bundle
    private Dictionary<string, Coroutine> loadingCoroutines = new Dictionary<string, Coroutine>();
    
    // 加载队列
    private Queue<BundleLoadRequest> loadQueue = new Queue<BundleLoadRequest>();
    private List<BundleLoadRequest> activeLoads = new List<BundleLoadRequest>();
    
    // Manifest缓存
    private AssetBundleManifest manifest;
    private bool isManifestLoaded = false;
    private Hash128 manifestHash;
    
    // 版本信息
    private Dictionary<string, Hash128> bundleHashes = new Dictionary<string, Hash128>();
    private Dictionary<string, long> bundleSizes = new Dictionary<string, long>();
    
    // 事件回调
    public event Action<string> OnBundleLoaded;
    public event Action<string, string> OnBundleLoadFailed;
    public event Action<long> OnMemoryWarning;
    #endregion

    #region 公共接口

    /// <summary>
    /// 初始化AssetBundle管理器
    /// </summary>
    public IEnumerator Initialize(BundleLoadMode loadMode = BundleLoadMode.Local)
    {
        Log("AssetBundleManager 初始化...");
        
        // 1. 加载Manifest
        yield return LoadManifest(loadMode);
        
        if (!isManifestLoaded)
        {
            LogError("Manifest加载失败!");
            yield break;
        }
        
        // 2. 加载版本信息
        yield return LoadVersionInfo(loadMode);
        
        // 3. 启动内存监控
        StartCoroutine(MemoryMonitor());
        
        // 4. 启动加载队列处理器
        StartCoroutine(ProcessLoadQueue());
        
        Log("AssetBundleManager 初始化完成");
    }

    /// <summary>
    /// 异步加载AssetBundle
    /// </summary>
    public void LoadBundleAsync(string bundleName, 
                                Action<AssetBundle> onComplete, 
                                BundleLoadPriority priority = BundleLoadPriority.Normal,
                                bool loadDependencies = true)
    {
        BundleLoadRequest request = new BundleLoadRequest
        {
            bundleName = bundleName,
            onComplete = onComplete,
            priority = (int)priority,
            loadDependencies = loadDependencies,
            requestTime = Time.time
        };
        
        // 添加到队列
        lock (loadQueue)
        {
            loadQueue.Enqueue(request);
        }
    }

    /// <summary>
    /// 同步加载AssetBundle(谨慎使用)
    /// </summary>
    public AssetBundle LoadBundleSync(string bundleName, bool loadDependencies = true)
    {
        if (IsBundleLoaded(bundleName))
        {
            IncreaseReference(bundleName);
            return loadedBundles[bundleName];
        }

        try
        {
            // 加载依赖
            if (loadDependencies && isManifestLoaded)
            {
                string[] dependencies = manifest.GetAllDependencies(bundleName);
                foreach (string dep in dependencies)
                {
                    if (!IsBundleLoaded(dep))
                    {
                        LoadBundleSync(dep, false);
                    }
                }
            }

            // 加载Bundle
            string path = GetBundlePath(bundleName, BundleLoadMode.Local);
            AssetBundle bundle = AssetBundle.LoadFromFile(path);
            
            if (bundle != null)
            {
                AddBundleToCache(bundleName, bundle);
                return bundle;
            }
        }
        catch (Exception e)
        {
            LogError($"同步加载Bundle失败: {bundleName}, Error: {e.Message}");
        }
        
        return null;
    }

    /// <summary>
    /// 异步加载资源
    /// </summary>
    public IEnumerator LoadAssetAsync<T>(string bundleName, string assetName, 
                                         Action<T> onComplete) where T : UnityEngine.Object
    {
        // 等待Bundle加载完成
        AssetBundle bundle = null;
        bool isLoaded = false;
        
        LoadBundleAsync(bundleName, (ab) => 
        {
            bundle = ab;
            isLoaded = true;
        });
        
        while (!isLoaded && bundle == null)
            yield return null;
        
        if (bundle == null)
        {
            onComplete?.Invoke(null);
            yield break;
        }
        
        // 异步加载资源
        AssetBundleRequest request = bundle.LoadAssetAsync<T>(assetName);
        yield return request;
        
        T asset = request.asset as T;
        onComplete?.Invoke(asset);
    }

    /// <summary>
    /// 卸载AssetBundle
    /// </summary>
    public void UnloadBundle(string bundleName, bool unloadAllLoadedObjects = false)
    {
        if (!loadedBundles.ContainsKey(bundleName))
        {
            LogWarning($"尝试卸载未加载的Bundle: {bundleName}");
            return;
        }

        BundleReferenceInfo info = bundleReferences[bundleName];
        info.referenceCount--;
        info.lastAccessTime = DateTime.Now;
        
        if (info.referenceCount <= 0 && !info.isPersistent)
        {
            StartCoroutine(UnloadBundleInternal(bundleName, unloadAllLoadedObjects));
        }
    }

    /// <summary>
    /// 强制卸载所有Bundle(场景切换时调用)
    /// </summary>
    public void UnloadAllBundles(bool unloadAllLoadedObjects = false)
    {
        List<string> bundlesToUnload = new List<string>(loadedBundles.Keys);
        
        foreach (string bundleName in bundlesToUnload)
        {
            if (bundleReferences.ContainsKey(bundleName) && 
                !bundleReferences[bundleName].isPersistent)
            {
                StartCoroutine(UnloadBundleInternal(bundleName, unloadAllLoadedObjects));
            }
        }
        
        // 清理未使用的资源
        StartCoroutine(CleanupUnusedAssets());
    }

    /// <summary>
    /// 设置Bundle常驻内存
    /// </summary>
    public void SetBundlePersistent(string bundleName, bool persistent)
    {
        if (bundleReferences.ContainsKey(bundleName))
        {
            bundleReferences[bundleName].isPersistent = persistent;
        }
    }

    /// <summary>
    /// 检查Bundle是否已加载
    /// </summary>
    public bool IsBundleLoaded(string bundleName)
    {
        return loadedBundles.ContainsKey(bundleName);
    }

    /// <summary>
    /// 获取Bundle信息
    /// </summary>
    public BundleReferenceInfo GetBundleInfo(string bundleName)
    {
        return bundleReferences.ContainsKey(bundleName) ? bundleReferences[bundleName] : null;
    }

    /// <summary>
    /// 获取所有已加载Bundle
    /// </summary>
    public List<string> GetAllLoadedBundles()
    {
        return new List<string>(loadedBundles.Keys);
    }

    /// <summary>
    /// 获取Bundle大小
    /// </summary>
    public long GetBundleSize(string bundleName)
    {
        if (bundleSizes.ContainsKey(bundleName))
            return bundleSizes[bundleName];
        
        string path = GetBundlePath(bundleName, BundleLoadMode.Local);
        if (File.Exists(path))
            return new FileInfo(path).Length;
        
        return 0;
    }

    /// <summary>
    /// 预加载常用Bundle
    /// </summary>
    public IEnumerator PreloadBundles(List<string> bundlesToPreload, Action<float> onProgress = null)
    {
        int total = bundlesToPreload.Count;
        int loaded = 0;
        
        foreach (string bundle in bundlesToPreload)
        {
            if (!IsBundleLoaded(bundle))
            {
                bool isLoaded = false;
                LoadBundleAsync(bundle, (ab) => isLoaded = true, BundleLoadPriority.Low);
                
                while (!isLoaded)
                    yield return null;
            }
            
            loaded++;
            onProgress?.Invoke((float)loaded / total);
        }
    }
    #endregion

    #region 内部实现

    /// <summary>
    /// 加载Manifest
    /// </summary>
    private IEnumerator LoadManifest(BundleLoadMode loadMode)
    {
        string platformFolder = GetPlatformFolder();
        string manifestBundleName = platformFolder;
        
        Log($"加载Manifest: {manifestBundleName}");
        
        AssetBundle bundle = null;
        string bundlePath = GetBundlePath(manifestBundleName, loadMode);
        
        if (loadMode == BundleLoadMode.Remote)
        {
            // 远程加载
            using (UnityWebRequest uwr = UnityWebRequestAssetBundle.GetAssetBundle(bundlePath, manifestHash, 0))
            {
                yield return uwr.SendWebRequest();
                
                if (uwr.result == UnityWebRequest.Result.Success)
                {
                    bundle = DownloadHandlerAssetBundle.GetContent(uwr);
                }
            }
        }
        else
        {
            // 本地加载
            if (File.Exists(bundlePath))
            {
                bundle = AssetBundle.LoadFromFile(bundlePath);
            }
        }
        
        if (bundle != null)
        {
            manifest = bundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
            bundle.Unload(false);
            isManifestLoaded = true;
            Log("Manifest加载成功");
        }
    }

    /// <summary>
    /// 加载版本信息
    /// </summary>
    private IEnumerator LoadVersionInfo(BundleLoadMode loadMode)
    {
        string versionPath = GetVersionFilePath(loadMode);
        
        if (loadMode == BundleLoadMode.Remote)
        {
            using (UnityWebRequest uwr = UnityWebRequest.Get(versionPath))
            {
                yield return uwr.SendWebRequest();
                
                if (uwr.result == UnityWebRequest.Result.Success)
                {
                    ParseVersionInfo(uwr.downloadHandler.text);
                }
            }
        }
        else if (File.Exists(versionPath))
        {
            string json = File.ReadAllText(versionPath);
            ParseVersionInfo(json);
        }
    }

    /// <summary>
    /// 解析版本信息
    /// </summary>
    private void ParseVersionInfo(string json)
    {
        try
        {
            BundleVersionInfo versionInfo = JsonUtility.FromJson<BundleVersionInfo>(json);
            
            foreach (BundleInfo info in versionInfo.bundles)
            {
                bundleHashes[info.name] = Hash128.Parse(info.hash);
                bundleSizes[info.name] = info.size;
            }
            
            Log($"版本信息加载完成,共{versionInfo.bundles.Count}个Bundle");
        }
        catch (Exception e)
        {
            LogWarning($"解析版本信息失败: {e.Message}");
        }
    }

    /// <summary>
    /// 处理加载队列
    /// </summary>
    private IEnumerator ProcessLoadQueue()
    {
        while (true)
        {
            // 检查是否有空闲的加载槽
            if (activeLoads.Count < maxConcurrentLoads && loadQueue.Count > 0)
            {
                BundleLoadRequest request;
                
                lock (loadQueue)
                {
                    request = loadQueue.Dequeue();
                }
                
                // 开始加载
                Coroutine coroutine = StartCoroutine(LoadBundleWithDependencies(request));
                activeLoads.Add(request);
                loadingCoroutines[request.bundleName] = coroutine;
            }
            
            // 清理已完成的任务
            activeLoads.RemoveAll(req => req.isCompleted);
            
            yield return null;
        }
    }

    /// <summary>
    /// 加载Bundle及其依赖
    /// </summary>
    private IEnumerator LoadBundleWithDependencies(BundleLoadRequest request)
    {
        string bundleName = request.bundleName;
        
        // 检查是否已加载
        if (IsBundleLoaded(bundleName))
        {
            IncreaseReference(bundleName);
            request.OnComplete(loadedBundles[bundleName]);
            request.isCompleted = true;
            yield break;
        }
        
        // 加载依赖
        if (request.loadDependencies && isManifestLoaded)
        {
            string[] dependencies = manifest.GetAllDependencies(bundleName);
            List<Coroutine> dependencyCoroutines = new List<Coroutine>();
            
            foreach (string dep in dependencies)
            {
                if (!IsBundleLoaded(dep) && !loadingCoroutines.ContainsKey(dep))
                {
                    BundleLoadRequest depRequest = new BundleLoadRequest
                    {
                        bundleName = dep,
                        priority = request.priority - 1, // 依赖优先级稍低
                        loadDependencies = false
                    };
                    
                    Coroutine depCoroutine = StartCoroutine(LoadSingleBundle(depRequest));
                    dependencyCoroutines.Add(depCoroutine);
                }
            }
            
            // 等待所有依赖加载完成
            foreach (Coroutine coroutine in dependencyCoroutines)
            {
                yield return coroutine;
            }
        }
        
        // 加载目标Bundle
        yield return LoadSingleBundle(request);
        
        // 记录依赖关系
        if (isManifestLoaded)
        {
            string[] dependencies = manifest.GetAllDependencies(bundleName);
            foreach (string dep in dependencies)
            {
                if (bundleReferences.ContainsKey(dep))
                {
                    bundleReferences[dep].dependentBundles.Add(bundleName);
                }
            }
        }
    }

    /// <summary>
    /// 加载单个Bundle
    /// </summary>
    private IEnumerator LoadSingleBundle(BundleLoadRequest request)
    {
        string bundleName = request.bundleName;
        BundleLoadState loadState = BundleLoadState.Loading;
        
        Log($"开始加载Bundle: {bundleName}");
        
        try
        {
            string path = GetBundlePath(bundleName, BundleLoadMode.Local);
            
            if (!File.Exists(path))
            {
                LogError($"Bundle文件不存在: {path}");
                loadState = BundleLoadState.Failed;
                request.OnError("文件不存在");
                yield break;
            }
            
            // 异步加载Bundle
            AssetBundleCreateRequest createRequest = AssetBundle.LoadFromFileAsync(path);
            yield return createRequest;
            
            if (createRequest.assetBundle == null)
            {
                LogError($"Bundle加载失败: {bundleName}");
                loadState = BundleLoadState.Failed;
                request.OnError("加载失败");
                yield break;
            }
            
            // 添加到缓存
            AddBundleToCache(bundleName, createRequest.assetBundle);
            loadState = BundleLoadState.Loaded;
            
            // 回调
            request.OnComplete(createRequest.assetBundle);
            OnBundleLoaded?.Invoke(bundleName);
            
            Log($"Bundle加载完成: {bundleName}");
        }
        catch (Exception e)
        {
            LogError($"加载Bundle异常: {bundleName}, Error: {e.Message}");
            loadState = BundleLoadState.Failed;
            request.OnError(e.Message);
            OnBundleLoadFailed?.Invoke(bundleName, e.Message);
        }
        finally
        {
            request.isCompleted = true;
            loadingCoroutines.Remove(bundleName);
        }
    }

    /// <summary>
    /// 卸载Bundle内部实现
    /// </summary>
    private IEnumerator UnloadBundleInternal(string bundleName, bool unloadAllLoadedObjects)
    {
        if (!loadedBundles.ContainsKey(bundleName))
            yield break;
        
        Log($"卸载Bundle: {bundleName}");
        
        AssetBundle bundle = loadedBundles[bundleName];
        BundleReferenceInfo info = bundleReferences[bundleName];
        
        // 先卸载依赖此Bundle的其他Bundle
        foreach (string dependentBundle in info.dependentBundles)
        {
            if (loadedBundles.ContainsKey(dependentBundle))
            {
                LogWarning($"Bundle {bundleName} 被 {dependentBundle} 依赖,先卸载依赖Bundle");
                UnloadBundle(dependentBundle, unloadAllLoadedObjects);
            }
        }
        
        // 等待一帧,让依赖Bundle先处理
        yield return null;
        
        // 卸载Bundle
        bundle.Unload(unloadAllLoadedObjects);
        loadedBundles.Remove(bundleName);
        bundleReferences.Remove(bundleName);
        
        // 触发GC(可选)
        if (unloadAllLoadedObjects)
        {
            yield return Resources.UnloadUnusedAssets();
        }
    }

    /// <summary>
    /// 添加Bundle到缓存
    /// </summary>
    private void AddBundleToCache(string bundleName, AssetBundle bundle)
    {
        if (!loadedBundles.ContainsKey(bundleName))
        {
            loadedBundles.Add(bundleName, bundle);
            
            if (!bundleReferences.ContainsKey(bundleName))
            {
                bundleReferences.Add(bundleName, new BundleReferenceInfo(bundleName));
            }
            
            bundleReferences[bundleName].referenceCount++;
            bundleReferences[bundleName].lastAccessTime = DateTime.Now;
            
            // 如果超过最大缓存数量,清理最久未使用的
            if (loadedBundles.Count > maxCacheBundles)
            {
                CleanupLeastUsedBundles();
            }
        }
    }

    /// <summary>
    /// 增加引用计数
    /// </summary>
    private void IncreaseReference(string bundleName)
    {
        if (bundleReferences.ContainsKey(bundleName))
        {
            bundleReferences[bundleName].referenceCount++;
            bundleReferences[bundleName].lastAccessTime = DateTime.Now;
        }
    }

    /// <summary>
    /// 清理最久未使用的Bundle
    /// </summary>
    private void CleanupLeastUsedBundles()
    {
        List<BundleReferenceInfo> infos = new List<BundleReferenceInfo>(bundleReferences.Values);
        
        // 按最后访问时间排序,排除常驻Bundle
        infos.Sort((a, b) => a.lastAccessTime.CompareTo(b.lastAccessTime));
        
        int bundlesToRemove = loadedBundles.Count - maxCacheBundles;
        int removed = 0;
        
        foreach (BundleReferenceInfo info in infos)
        {
            if (removed >= bundlesToRemove) break;
            
            if (!info.isPersistent && info.referenceCount <= 0)
            {
                StartCoroutine(UnloadBundleInternal(info.bundleName, false));
                removed++;
            }
        }
    }

    /// <summary>
    /// 清理未使用的资源
    /// </summary>
    private IEnumerator CleanupUnusedAssets()
    {
        yield return new WaitForSeconds(unloadUnusedDelay);
        
        Log("开始清理未使用资源...");
        
        AsyncOperation asyncOp = Resources.UnloadUnusedAssets();
        yield return asyncOp;
        
        GC.Collect();
        
        Log($"资源清理完成,释放内存: {Profiler.GetTotalAllocatedMemoryLong() / 1024 / 1024}MB");
    }

    /// <summary>
    /// 内存监控
    /// </summary>
    private IEnumerator MemoryMonitor()
    {
        while (true)
        {
            yield return new WaitForSeconds(10f);
            
            long totalMemory = Profiler.GetTotalAllocatedMemoryLong();
            
            if (totalMemory > memoryThreshold)
            {
                LogWarning($"内存使用过高: {totalMemory / 1024 / 1024}MB");
                OnMemoryWarning?.Invoke(totalMemory);
                
                // 自动清理
                UnloadAllBundles(false);
            }
        }
    }

    /// <summary>
    /// 获取Bundle路径
    /// </summary>
    private string GetBundlePath(string bundleName, BundleLoadMode mode)
    {
        string platformFolder = GetPlatformFolder();
        
        switch (mode)
        {
            case BundleLoadMode.Remote:
                return $"{remoteBundleUrl}{platformFolder}/{bundleName}";
                
            case BundleLoadMode.Persistent:
                return $"{Application.persistentDataPath}/{localBundlePath}/{platformFolder}/{bundleName}";
                
            case BundleLoadMode.Local:
            default:
                #if UNITY_EDITOR || UNITY_STANDALONE
                return $"{Application.dataPath}/../{localBundlePath}/{platformFolder}/{bundleName}";
                #else
                return $"{Application.streamingAssetsPath}/{localBundlePath}/{platformFolder}/{bundleName}";
                #endif
        }
    }

    /// <summary>
    /// 获取版本文件路径
    /// </summary>
    private string GetVersionFilePath(BundleLoadMode mode)
    {
        string platformFolder = GetPlatformFolder();
        
        switch (mode)
        {
            case BundleLoadMode.Remote:
                return $"{remoteBundleUrl}{platformFolder}/version.json";
                
            default:
                string bundlePath = GetBundlePath("", mode);
                return Path.Combine(Path.GetDirectoryName(bundlePath), "version.json");
        }
    }

    /// <summary>
    /// 获取平台文件夹名称
    /// </summary>
    private string GetPlatformFolder()
    {
        #if UNITY_EDITOR
        return GetPlatformForAssetBundles(UnityEditor.EditorUserBuildSettings.activeBuildTarget);
        #else
        return GetPlatformForAssetBundles(Application.platform);
        #endif
    }

    private string GetPlatformForAssetBundles(RuntimePlatform platform)
    {
        switch (platform)
        {
            case RuntimePlatform.Android:
                return "Android";
            case RuntimePlatform.IPhonePlayer:
                return "iOS";
            case RuntimePlatform.WebGLPlayer:
                return "WebGL";
            case RuntimePlatform.WindowsPlayer:
            case RuntimePlatform.WindowsEditor:
                return "Windows";
            case RuntimePlatform.OSXPlayer:
            case RuntimePlatform.OSXEditor:
                return "OSX";
            default:
                return platform.ToString();
        }
    }

    #if UNITY_EDITOR
    private string GetPlatformForAssetBundles(UnityEditor.BuildTarget target)
    {
        switch (target)
        {
            case UnityEditor.BuildTarget.Android:
                return "Android";
            case UnityEditor.BuildTarget.iOS:
                return "iOS";
            case UnityEditor.BuildTarget.WebGL:
                return "WebGL";
            case UnityEditor.BuildTarget.StandaloneWindows:
            case UnityEditor.BuildTarget.StandaloneWindows64:
                return "Windows";
            case UnityEditor.BuildTarget.StandaloneOSX:
                return "OSX";
            default:
                return target.ToString();
        }
    }
    #endif

    /// <summary>
    /// 日志输出
    /// </summary>
    private void Log(string message)
    {
        if (enableLog)
            Debug.Log($"[AssetBundleManager] {message}");
    }

    private void LogWarning(string message)
    {
        Debug.LogWarning($"[AssetBundleManager] {message}");
    }

    private void LogError(string message)
    {
        Debug.LogError($"[AssetBundleManager] {message}");
    }
    #endregion

    #region 辅助类

    /// <summary>
    /// Bundle加载请求
    /// </summary>
    private class BundleLoadRequest
    {
        public string bundleName;
        public Action<AssetBundle> onComplete;
        public Action<string> onError;
        public int priority;
        public bool loadDependencies;
        public float requestTime;
        public bool isCompleted;
        
        public void OnComplete(AssetBundle bundle)
        {
            onComplete?.Invoke(bundle);
        }
        
        public void OnError(string error)
        {
            onError?.Invoke(error);
        }
    }

    /// <summary>
    /// Bundle版本信息
    /// </summary>
    [System.Serializable]
    private class BundleVersionInfo
    {
        public int version;
        public string buildTime;
        public List<BundleInfo> bundles;
    }

    [System.Serializable]
    private class BundleInfo
    {
        public string name;
        public string hash;
        public long size;
        public List<string> dependencies;
    }
    #endregion

    #region Unity生命周期

    void OnApplicationQuit()
    {
        // 游戏退出时清理所有Bundle
        UnloadAllBundles(true);
    }

    void OnApplicationPause(bool pauseStatus)
    {
        if (pauseStatus)
        {
            // 应用暂停时清理部分资源
            CleanupLeastUsedBundles();
        }
    }
    #endregion
}

三、AssetBundle 加载方式对比

3.1 同步加载方法

csharp

public class AssetBundleLoader
{
    // 方法1:从文件同步加载(推荐)
    public void LoadFromFile()
    {
        string path = Application.streamingAssetsPath + "/bundle_name";
        AssetBundle bundle = AssetBundle.LoadFromFile(path);
        
        if (bundle != null)
        {
            GameObject prefab = bundle.LoadAsset<GameObject>("asset_name");
            Instantiate(prefab);
        }
    }
    
    // 方法2:从内存同步加载
    public void LoadFromMemory(byte[] binaryData)
    {
        AssetBundle bundle = AssetBundle.LoadFromMemory(binaryData);
        // 使用资源...
    }
}

3.2 异步加载方法

csharp

public class AssetBundleAsyncLoader : MonoBehaviour
{
    // 方法1:异步加载 AssetBundle
    public IEnumerator LoadBundleAsync(string bundlePath)
    {
        AssetBundleCreateRequest request = 
            AssetBundle.LoadFromFileAsync(bundlePath);
        
        yield return request;
        
        AssetBundle bundle = request.assetBundle;
        if (bundle != null)
        {
            // 异步加载资源
            AssetBundleRequest assetRequest = 
                bundle.LoadAssetAsync<GameObject>("prefab_name");
            yield return assetRequest;
            
            GameObject prefab = assetRequest.asset as GameObject;
            Instantiate(prefab);
        }
    }
    
    // 方法2:使用 UnityWebRequest(支持网络加载)
    public IEnumerator LoadBundleWebRequest(string url)
    {
        using (UnityWebRequest webRequest = 
            UnityWebRequestAssetBundle.GetAssetBundle(url))
        {
            yield return webRequest.SendWebRequest();
            
            if (webRequest.result == UnityWebRequest.Result.Success)
            {
                AssetBundle bundle = 
                    DownloadHandlerAssetBundle.GetContent(webRequest);
                // 使用资源...
            }
        }
    }
}

3.3 加载方式对比表

加载方式适用场景内存占用加载速度推荐指数
LoadFromFile本地 StreamingAssets★★★★★
LoadFromMemory加密资源、内存数据★★☆☆☆
LoadFromFileAsync大资源加载★★★★☆
UnityWebRequest网络下载、热更新依赖网络★★★★☆

四、依赖管理最佳实践

4.1 依赖加载实现

csharp

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Networking;

/// <summary>
/// 依赖关系解析模式
/// </summary>
public enum DependencyResolutionMode
{
    Eager,      // 急加载:立即加载所有依赖
    Lazy,       // 懒加载:按需加载依赖
    Hybrid      // 混合模式:急加载直接依赖,懒加载间接依赖
}

/// <summary>
/// 依赖关系图节点
/// </summary>
public class DependencyNode
{
    public string bundleName;
    public List<DependencyNode> dependencies;       // 依赖的节点
    public List<DependencyNode> dependents;         // 依赖此节点的节点
    public int referenceCount;                     // 引用计数
    public bool isLoaded;                          // 是否已加载
    public bool isRoot;                            // 是否是根节点(用户显式加载的)
    public DateTime lastAccessTime;               // 最后访问时间
    
    public DependencyNode(string name)
    {
        bundleName = name;
        dependencies = new List<DependencyNode>();
        dependents = new List<DependencyNode>();
        referenceCount = 0;
        isLoaded = false;
        isRoot = false;
        lastAccessTime = DateTime.Now;
    }
    
    /// <summary>
    /// 获取所有直接和间接依赖
    /// </summary>
    public List<DependencyNode> GetAllDependencies(bool includeSelf = false)
    {
        List<DependencyNode> result = new List<DependencyNode>();
        HashSet<DependencyNode> visited = new HashSet<DependencyNode>();
        
        if (includeSelf)
        {
            result.Add(this);
            visited.Add(this);
        }
        
        GetAllDependenciesRecursive(this, result, visited);
        return result;
    }
    
    private void GetAllDependenciesRecursive(DependencyNode node, 
                                           List<DependencyNode> result, 
                                           HashSet<DependencyNode> visited)
    {
        foreach (var dep in node.dependencies)
        {
            if (!visited.Contains(dep))
            {
                visited.Add(dep);
                result.Add(dep);
                GetAllDependenciesRecursive(dep, result, visited);
            }
        }
    }
    
    /// <summary>
    /// 获取所有直接和间接依赖者
    /// </summary>
    public List<DependencyNode> GetAllDependents()
    {
        List<DependencyNode> result = new List<DependencyNode>();
        HashSet<DependencyNode> visited = new HashSet<DependencyNode>();
        
        GetAllDependentsRecursive(this, result, visited);
        return result;
    }
    
    private void GetAllDependentsRecursive(DependencyNode node, 
                                         List<DependencyNode> result, 
                                         HashSet<DependencyNode> visited)
    {
        foreach (var dependent in node.dependents)
        {
            if (!visited.Contains(dependent))
            {
                visited.Add(dependent);
                result.Add(dependent);
                GetAllDependentsRecursive(dependent, result, visited);
            }
        }
    }
    
    /// <summary>
    /// 检查循环依赖
    /// </summary>
    public bool HasCircularDependency()
    {
        HashSet<DependencyNode> visited = new HashSet<DependencyNode>();
        HashSet<DependencyNode> recursionStack = new HashSet<DependencyNode>();
        
        return CheckCircularDependencyRecursive(this, visited, recursionStack);
    }
    
    private bool CheckCircularDependencyRecursive(DependencyNode node, 
                                                HashSet<DependencyNode> visited, 
                                                HashSet<DependencyNode> recursionStack)
    {
        visited.Add(node);
        recursionStack.Add(node);
        
        foreach (var dep in node.dependencies)
        {
            if (!visited.Contains(dep))
            {
                if (CheckCircularDependencyRecursive(dep, visited, recursionStack))
                    return true;
            }
            else if (recursionStack.Contains(dep))
            {
                return true; // 发现循环依赖
            }
        }
        
        recursionStack.Remove(node);
        return false;
    }
}

/// <summary>
/// 依赖加载任务
/// </summary>
public class DependencyLoadTask
{
    public string bundleName;
    public List<string> dependencies;
    public Action<AssetBundle> onComplete;
    public Action<string> onError;
    public bool loadDependencies;
    public int priority;
    
    public DependencyLoadTask(string bundleName)
    {
        this.bundleName = bundleName;
        dependencies = new List<string>();
        loadDependencies = true;
        priority = 1;
    }
}

/// <summary>
/// 依赖关系图
/// </summary>
public class DependencyGraph
{
    private Dictionary<string, DependencyNode> nodes = new Dictionary<string, DependencyNode>();
    
    public bool AddNode(string bundleName)
    {
        if (!nodes.ContainsKey(bundleName))
        {
            nodes[bundleName] = new DependencyNode(bundleName);
            return true;
        }
        return false;
    }
    
    public bool AddDependency(string fromBundle, string toBundle)
    {
        if (!nodes.ContainsKey(fromBundle))
            AddNode(fromBundle);
        if (!nodes.ContainsKey(toBundle))
            AddNode(toBundle);
        
        DependencyNode fromNode = nodes[fromBundle];
        DependencyNode toNode = nodes[toBundle];
        
        // 检查是否已存在此依赖
        if (!fromNode.dependencies.Contains(toNode))
        {
            fromNode.dependencies.Add(toNode);
            toNode.dependents.Add(fromNode);
            
            // 检查是否创建了循环依赖
            if (fromNode.HasCircularDependency())
            {
                // 回滚
                fromNode.dependencies.Remove(toNode);
                toNode.dependents.Remove(fromNode);
                Debug.LogError($"添加依赖 {fromBundle} -> {toBundle} 会导致循环依赖!");
                return false;
            }
            
            return true;
        }
        
        return false;
    }
    
    public DependencyNode GetNode(string bundleName)
    {
        nodes.TryGetValue(bundleName, out DependencyNode node);
        return node;
    }
    
    public List<string> GetAllDependencies(string bundleName, bool includeSelf = false)
    {
        if (!nodes.TryGetValue(bundleName, out DependencyNode node))
            return new List<string>();
        
        var dependencyNodes = node.GetAllDependencies(includeSelf);
        return dependencyNodes.Select(n => n.bundleName).ToList();
    }
    
    public List<string> GetDirectDependencies(string bundleName)
    {
        if (!nodes.TryGetValue(bundleName, out DependencyNode node))
            return new List<string>();
        
        return node.dependencies.Select(d => d.bundleName).ToList();
    }
    
    public List<string> GetDirectDependents(string bundleName)
    {
        if (!nodes.TryGetValue(bundleName, out DependencyNode node))
            return new List<string>();
        
        return node.dependents.Select(d => d.bundleName).ToList();
    }
    
    public List<string> GetAllDependents(string bundleName)
    {
        if (!nodes.TryGetValue(bundleName, out DependencyNode node))
            return new List<string>();
        
        var dependentNodes = node.GetAllDependents();
        return dependentNodes.Select(n => n.bundleName).ToList();
    }
    
    /// <summary>
    /// 拓扑排序,获取加载顺序
    /// </summary>
    public List<string> GetLoadOrder(List<string> bundles)
    {
        List<string> result = new List<string>();
        HashSet<string> visited = new HashSet<string>();
        HashSet<string> tempMark = new HashSet<string>();
        
        foreach (string bundle in bundles)
        {
            if (!visited.Contains(bundle))
            {
                if (!TopologicalSort(bundle, visited, tempMark, result))
                {
                    Debug.LogError("发现循环依赖,无法确定加载顺序");
                    return new List<string>();
                }
            }
        }
        
        result.Reverse(); // 拓扑排序结果是逆序的,反转后得到正确的加载顺序
        return result;
    }
    
    private bool TopologicalSort(string bundleName, 
                                HashSet<string> visited, 
                                HashSet<string> tempMark, 
                                List<string> result)
    {
        if (!nodes.ContainsKey(bundleName))
            return true;
            
        if (tempMark.Contains(bundleName))
            return false; // 发现循环依赖
            
        if (visited.Contains(bundleName))
            return true;
            
        tempMark.Add(bundleName);
        
        foreach (var dep in nodes[bundleName].dependencies)
        {
            if (!TopologicalSort(dep.bundleName, visited, tempMark, result))
                return false;
        }
        
        tempMark.Remove(bundleName);
        visited.Add(bundleName);
        result.Add(bundleName);
        
        return true;
    }
    
    /// <summary>
    /// 获取逆拓扑排序,用于卸载
    /// </summary>
    public List<string> GetUnloadOrder(List<string> bundles)
    {
        var loadOrder = GetLoadOrder(bundles);
        loadOrder.Reverse(); // 卸载顺序是加载顺序的逆序
        return loadOrder;
    }
    
    public bool HasCircularDependency(string bundleName = null)
    {
        if (bundleName != null)
        {
            if (nodes.TryGetValue(bundleName, out DependencyNode node))
                return node.HasCircularDependency();
            return false;
        }
        
        // 检查整个图的循环依赖
        foreach (var node in nodes.Values)
        {
            if (node.HasCircularDependency())
                return true;
        }
        
        return false;
    }
    
    public void Clear()
    {
        nodes.Clear();
    }
    
    public int NodeCount => nodes.Count;
}

/// <summary>
/// 完善的依赖关系管理器
/// </summary>
public class DependencyManager : MonoBehaviour
{
    #region 单例模式
    private static DependencyManager _instance;
    public static DependencyManager Instance
    {
        get
        {
            if (_instance == null)
            {
                GameObject go = new GameObject("DependencyManager");
                _instance = go.AddComponent<DependencyManager>();
                DontDestroyOnLoad(go);
            }
            return _instance;
        }
    }
    #endregion

    #region 配置参数
    [Header("依赖管理配置")]
    [SerializeField] private bool enableLog = true;
    [SerializeField] private DependencyResolutionMode resolutionMode = DependencyResolutionMode.Hybrid;
    [SerializeField] private bool autoResolveCircularDependencies = true;
    [SerializeField] private int maxDependencyDepth = 10; // 最大依赖深度
    
    [Header("性能优化")]
    [SerializeField] private bool enableDependencyCaching = true;
    [SerializeField] private int dependencyCacheSize = 50;
    [SerializeField] private bool preloadCommonDependencies = true;
    [SerializeField] private List<string> commonDependencies = new List<string> { "shared", "common", "core" };
    #endregion

    #region 内部数据结构
    // 依赖关系图
    private DependencyGraph dependencyGraph = new DependencyGraph();
    
    // Manifest引用
    private AssetBundleManifest manifest;
    private bool isManifestLoaded = false;
    
    // 依赖缓存
    private Dictionary<string, List<string>> dependencyCache = new Dictionary<string, List<string>>();
    private Dictionary<string, DateTime> cacheTimestamps = new Dictionary<string, DateTime>();
    
    // 加载状态跟踪
    private Dictionary<string, DependencyLoadTask> activeTasks = new Dictionary<string, DependencyLoadTask>();
    private Dictionary<string, List<DependencyLoadTask>> waitingTasks = new Dictionary<string, List<DependencyLoadTask>>();
    
    // 依赖加载队列
    private PriorityQueue<DependencyLoadTask> loadQueue = new PriorityQueue<DependencyLoadTask>(
        Comparer<DependencyLoadTask>.Create((a, b) => b.priority.CompareTo(a.priority))
    );
    
    // 统计信息
    private DependencyStats stats = new DependencyStats();
    
    // 事件
    public event Action<string, List<string>> OnDependenciesResolved;
    public event Action<string> OnCircularDependencyDetected;
    public event Action<DependencyStats> OnStatsUpdated;
    #endregion

    #region 公共接口

    /// <summary>
    /// 初始化依赖管理器
    /// </summary>
    public IEnumerator Initialize(AssetBundleManifest manifest)
    {
        if (manifest == null)
        {
            Debug.LogError("DependencyManager: Manifest不能为空");
            yield break;
        }
        
        this.manifest = manifest;
        isManifestLoaded = true;
        
        // 构建依赖关系图
        yield return BuildDependencyGraph();
        
        // 预加载常用依赖
        if (preloadCommonDependencies)
        {
            yield return PreloadCommonDependencies();
        }
        
        // 启动依赖处理器
        StartCoroutine(ProcessDependencyQueue());
        
        Log("DependencyManager 初始化完成");
    }

    /// <summary>
    /// 解析Bundle的依赖关系
    /// </summary>
    public DependencyResult ResolveDependencies(string bundleName, 
                                              bool includeSelf = false, 
                                              bool forceRefresh = false)
    {
        if (!isManifestLoaded)
        {
            return new DependencyResult
            {
                success = false,
                error = "Manifest未加载"
            };
        }
        
        // 检查缓存
        if (!forceRefresh && enableDependencyCaching && dependencyCache.ContainsKey(bundleName))
        {
            DateTime lastUpdate = cacheTimestamps[bundleName];
            if ((DateTime.Now - lastUpdate).TotalMinutes < 5) // 5分钟缓存
            {
                stats.cacheHits++;
                return new DependencyResult
                {
                    success = true,
                    dependencies = dependencyCache[bundleName],
                    fromCache = true
                };
            }
        }
        
        try
        {
            List<string> allDependencies = new List<string>();
            
            // 获取直接依赖
            string[] directDeps = manifest.GetAllDependencies(bundleName);
            
            // 检查依赖深度
            int depth = CalculateDependencyDepth(bundleName, new HashSet<string>());
            if (depth > maxDependencyDepth)
            {
                LogWarning($"Bundle {bundleName} 的依赖深度({depth})超过限制({maxDependencyDepth})");
                return new DependencyResult
                {
                    success = false,
                    error = $"依赖深度超过限制: {depth} > {maxDependencyDepth}"
                };
            }
            
            // 根据模式解析依赖
            switch (resolutionMode)
            {
                case DependencyResolutionMode.Eager:
                    allDependencies = GetAllDependenciesEager(bundleName);
                    break;
                    
                case DependencyResolutionMode.Lazy:
                    allDependencies = new List<string>(directDeps);
                    break;
                    
                case DependencyResolutionMode.Hybrid:
                    allDependencies = GetDependenciesHybrid(bundleName);
                    break;
            }
            
            // 去重
            allDependencies = allDependencies.Distinct().ToList();
            
            if (includeSelf)
            {
                allDependencies.Insert(0, bundleName);
            }
            
            // 缓存结果
            if (enableDependencyCaching)
            {
                CacheDependencies(bundleName, allDependencies);
            }
            
            stats.dependencyResolutions++;
            OnStatsUpdated?.Invoke(stats);
            
            return new DependencyResult
            {
                success = true,
                dependencies = allDependencies,
                directDependencies = directDeps.ToList(),
                dependencyDepth = depth,
                fromCache = false
            };
        }
        catch (Exception e)
        {
            LogError($"解析依赖失败: {bundleName}, Error: {e.Message}");
            return new DependencyResult
            {
                success = false,
                error = e.Message
            };
        }
    }

    /// <summary>
    /// 创建依赖加载任务
    /// </summary>
    public DependencyLoadTask CreateLoadTask(string bundleName, 
                                           Action<AssetBundle> onComplete = null, 
                                           Action<string> onError = null,
                                           int priority = 1)
    {
        var result = ResolveDependencies(bundleName);
        
        if (!result.success)
        {
            onError?.Invoke($"无法解析依赖: {result.error}");
            return null;
        }
        
        var task = new DependencyLoadTask(bundleName)
        {
            onComplete = onComplete,
            onError = onError,
            priority = priority,
            dependencies = result.dependencies
        };
        
        // 检查循环依赖
        if (HasCircularDependency(bundleName))
        {
            HandleCircularDependency(bundleName);
            return null;
        }
        
        return task;
    }

    /// <summary>
    /// 提交依赖加载任务
    /// </summary>
    public void SubmitLoadTask(DependencyLoadTask task)
    {
        if (task == null) return;
        
        lock (loadQueue)
        {
            loadQueue.Enqueue(task);
        }
        
        stats.tasksSubmitted++;
        Log($"提交加载任务: {task.bundleName}, 优先级: {task.priority}");
    }

    /// <summary>
    /// 获取Bundle的依赖树
    /// </summary>
    public DependencyTree GetDependencyTree(string bundleName, bool includeSelf = true)
    {
        var tree = new DependencyTree
        {
            rootBundle = bundleName,
            nodes = new List<DependencyTreeNode>()
        };
        
        BuildDependencyTreeRecursive(bundleName, tree, 0, new HashSet<string>());
        return tree;
    }

    /// <summary>
    /// 可视化依赖关系
    /// </summary>
    public string VisualizeDependencies(string bundleName, bool includeIndirect = true)
    {
        StringBuilder sb = new StringBuilder();
        
        if (includeIndirect)
        {
            var allDeps = GetAllDependenciesEager(bundleName);
            sb.AppendLine($"Bundle: {bundleName}");
            sb.AppendLine($"总依赖数: {allDeps.Count}");
            sb.AppendLine("依赖关系:");
            
            foreach (string dep in allDeps)
            {
                int depth = CalculateDependencyDepth(dep, new HashSet<string>());
                string indent = new string(' ', depth * 2);
                sb.AppendLine($"{indent}└─ {dep}");
            }
        }
        else
        {
            string[] directDeps = manifest.GetDirectDependencies(bundleName);
            sb.AppendLine($"Bundle: {bundleName}");
            sb.AppendLine($"直接依赖数: {directDeps.Length}");
            
            foreach (string dep in directDeps)
            {
                sb.AppendLine($"  └─ {dep}");
            }
        }
        
        return sb.ToString();
    }

    /// <summary>
    /// 检查是否存在循环依赖
    /// </summary>
    public bool HasCircularDependency(string bundleName = null)
    {
        return dependencyGraph.HasCircularDependency(bundleName);
    }

    /// <summary>
    /// 分析依赖关系健康度
    /// </summary>
    public DependencyHealthReport AnalyzeDependencyHealth()
    {
        var report = new DependencyHealthReport
        {
            totalBundles = dependencyGraph.NodeCount,
            analyzedAt = DateTime.Now
        };
        
        List<string> problematicBundles = new List<string>();
        
        foreach (var node in GetAllNodes())
        {
            var deps = GetAllDependenciesEager(node);
            
            // 检查深度
            int depth = CalculateDependencyDepth(node, new HashSet<string>());
            if (depth > maxDependencyDepth)
            {
                report.deepDependencies++;
                problematicBundles.Add(node);
            }
            
            // 检查循环依赖
            if (HasCircularDependency(node))
            {
                report.circularDependencies++;
                problematicBundles.Add(node);
            }
            
            // 检查过度耦合
            int dependentCount = GetDirectDependents(node).Count;
            if (dependentCount > 10) // 假设超过10个依赖者视为过度耦合
            {
                report.highCouplingBundles++;
                problematicBundles.Add(node);
            }
        }
        
        report.problematicBundles = problematicBundles.Distinct().ToList();
        report.healthScore = CalculateHealthScore(report);
        
        return report;
    }

    /// <summary>
    /// 优化依赖关系
    /// </summary>
    public IEnumerator OptimizeDependencies(List<string> frequentlyUsedBundles)
    {
        Log("开始依赖关系优化...");
        
        // 1. 合并常用依赖
        yield return MergeCommonDependencies(frequentlyUsedBundles);
        
        // 2. 重构深度依赖
        yield return RefactorDeepDependencies();
        
        // 3. 清理无用依赖
        yield return CleanupUnusedDependencies();
        
        Log("依赖关系优化完成");
    }

    /// <summary>
    /// 获取统计信息
    /// </summary>
    public DependencyStats GetStats()
    {
        return stats;
    }

    /// <summary>
    /// 清理缓存
    /// </summary>
    public void ClearCache()
    {
        dependencyCache.Clear();
        cacheTimestamps.Clear();
        Log("依赖缓存已清理");
    }

    /// <summary>
    /// 重新加载依赖关系
    /// </summary>
    public IEnumerator ReloadDependencies(AssetBundleManifest newManifest)
    {
        manifest = newManifest;
        dependencyGraph.Clear();
        ClearCache();
        
        yield return BuildDependencyGraph();
        Log("依赖关系已重新加载");
    }
    #endregion

    #region 内部实现

    /// <summary>
    /// 构建依赖关系图
    /// </summary>
    private IEnumerator BuildDependencyGraph()
    {
        if (manifest == null)
            yield break;
        
        string[] allBundles = manifest.GetAllAssetBundles();
        int processed = 0;
        
        foreach (string bundle in allBundles)
        {
            dependencyGraph.AddNode(bundle);
            
            string[] dependencies = manifest.GetAllDependencies(bundle);
            foreach (string dep in dependencies)
            {
                dependencyGraph.AddDependency(bundle, dep);
            }
            
            processed++;
            
            // 每处理100个Bundle给一帧休息时间
            if (processed % 100 == 0)
            {
                yield return null;
            }
        }
        
        Log($"依赖关系图构建完成,共{allBundles.Length}个Bundle");
    }

    /// <summary>
    /// 急加载模式:获取所有依赖
    /// </summary>
    private List<string> GetAllDependenciesEager(string bundleName)
    {
        List<string> allDependencies = new List<string>();
        HashSet<string> visited = new HashSet<string>();
        
        GetAllDependenciesRecursive(bundleName, allDependencies, visited);
        return allDependencies;
    }

    private void GetAllDependenciesRecursive(string bundleName, 
                                           List<string> result, 
                                           HashSet<string> visited)
    {
        if (!isManifestLoaded || visited.Contains(bundleName))
            return;
            
        visited.Add(bundleName);
        
        string[] dependencies = manifest.GetAllDependencies(bundleName);
        foreach (string dep in dependencies)
        {
            GetAllDependenciesRecursive(dep, result, visited);
            if (!result.Contains(dep))
            {
                result.Add(dep);
            }
        }
    }

    /// <summary>
    /// 混合模式:获取依赖
    /// </summary>
    private List<string> GetDependenciesHybrid(string bundleName)
    {
        List<string> result = new List<string>();
        HashSet<string> visited = new HashSet<string>();
        
        GetDependenciesHybridRecursive(bundleName, result, visited, 0);
        return result;
    }

    private void GetDependenciesHybridRecursive(string bundleName, 
                                              List<string> result, 
                                              HashSet<string> visited, 
                                              int depth)
    {
        if (!isManifestLoaded || visited.Contains(bundleName))
            return;
            
        visited.Add(bundleName);
        
        string[] dependencies = manifest.GetAllDependencies(bundleName);
        
        // 直接依赖总是加载
        foreach (string dep in dependencies)
        {
            if (!result.Contains(dep))
            {
                result.Add(dep);
            }
        }
        
        // 深度超过1的间接依赖按需加载
        if (depth < 1)
        {
            foreach (string dep in dependencies)
            {
                GetDependenciesHybridRecursive(dep, result, visited, depth + 1);
            }
        }
    }

    /// <summary>
    /// 计算依赖深度
    /// </summary>
    private int CalculateDependencyDepth(string bundleName, HashSet<string> visited)
    {
        if (!isManifestLoaded || visited.Contains(bundleName))
            return 0;
            
        visited.Add(bundleName);
        
        string[] dependencies = manifest.GetAllDependencies(bundleName);
        int maxDepth = 0;
        
        foreach (string dep in dependencies)
        {
            int depth = CalculateDependencyDepth(dep, visited) + 1;
            maxDepth = Mathf.Max(maxDepth, depth);
        }
        
        return maxDepth;
    }

    /// <summary>
    /// 缓存依赖关系
    /// </summary>
    private void CacheDependencies(string bundleName, List<string> dependencies)
    {
        // 如果缓存已满,移除最旧的
        if (dependencyCache.Count >= dependencyCacheSize)
        {
            string oldestKey = null;
            DateTime oldestTime = DateTime.MaxValue;
            
            foreach (var kvp in cacheTimestamps)
            {
                if (kvp.Value < oldestTime)
                {
                    oldestTime = kvp.Value;
                    oldestKey = kvp.Key;
                }
            }
            
            if (oldestKey != null)
            {
                dependencyCache.Remove(oldestKey);
                cacheTimestamps.Remove(oldestKey);
            }
        }
        
        dependencyCache[bundleName] = dependencies;
        cacheTimestamps[bundleName] = DateTime.Now;
    }

    /// <summary>
    /// 处理循环依赖
    /// </summary>
    private void HandleCircularDependency(string bundleName)
    {
        LogError($"检测到循环依赖: {bundleName}");
        
        if (autoResolveCircularDependencies)
        {
            LogWarning($"尝试自动修复循环依赖: {bundleName}");
            // 这里可以实现自动修复逻辑,比如移除最弱的依赖
            // 暂时只是记录日志
        }
        
        OnCircularDependencyDetected?.Invoke(bundleName);
    }

    /// <summary>
    /// 处理依赖加载队列
    /// </summary>
    private IEnumerator ProcessDependencyQueue()
    {
        while (true)
        {
            DependencyLoadTask task = null;
            
            lock (loadQueue)
            {
                if (loadQueue.Count > 0)
                {
                    task = loadQueue.Dequeue();
                }
            }
            
            if (task != null)
            {
                yield return StartCoroutine(ExecuteDependencyLoadTask(task));
            }
            
            yield return null;
        }
    }

    /// <summary>
    /// 执行依赖加载任务
    /// </summary>
    private IEnumerator ExecuteDependencyLoadTask(DependencyLoadTask task)
    {
        Log($"开始执行依赖加载任务: {task.bundleName}");
        
        try
        {
            // 获取加载顺序
            var loadOrder = dependencyGraph.GetLoadOrder(task.dependencies);
            
            // 按顺序加载依赖
            foreach (string dep in loadOrder)
            {
                if (!IsBundleLoaded(dep))
                {
                    yield return LoadDependencyAsync(dep);
                }
            }
            
            // 加载目标Bundle
            yield return LoadTargetBundle(task);
            
            stats.tasksCompleted++;
            OnStatsUpdated?.Invoke(stats);
        }
        catch (Exception e)
        {
            task.onError?.Invoke($"依赖加载失败: {e.Message}");
            stats.tasksFailed++;
        }
    }

    /// <summary>
    /// 异步加载依赖
    /// </summary>
    private IEnumerator LoadDependencyAsync(string bundleName)
    {
        // 这里应该调用AssetBundleManager的加载方法
        // 为了简化示例,这里使用伪代码
        yield return null;
    }

    /// <summary>
    /// 加载目标Bundle
    /// </summary>
    private IEnumerator LoadTargetBundle(DependencyLoadTask task)
    {
        // 这里应该调用AssetBundleManager的加载方法
        yield return null;
        
        // 模拟加载完成
        task.onComplete?.Invoke(null);
    }

    /// <summary>
    /// 构建依赖树(递归)
    /// </summary>
    private void BuildDependencyTreeRecursive(string bundleName, 
                                            DependencyTree tree, 
                                            int depth, 
                                            HashSet<string> visited)
    {
        if (visited.Contains(bundleName))
            return;
            
        visited.Add(bundleName);
        
        var node = new DependencyTreeNode
        {
            bundleName = bundleName,
            depth = depth
        };
        
        tree.nodes.Add(node);
        
        string[] dependencies = manifest.GetAllDependencies(bundleName);
        foreach (string dep in dependencies)
        {
            node.dependencies.Add(dep);
            BuildDependencyTreeRecursive(dep, tree, depth + 1, visited);
        }
    }

    /// <summary>
    /// 获取所有节点
    /// </summary>
    private List<string> GetAllNodes()
    {
        return new List<string>(dependencyCache.Keys);
    }

    /// <summary>
    /// 获取直接依赖者
    /// </summary>
    private List<string> GetDirectDependents(string bundleName)
    {
        return dependencyGraph.GetDirectDependents(bundleName);
    }

    /// <summary>
    /// 检查Bundle是否已加载
    /// </summary>
    private bool IsBundleLoaded(string bundleName)
    {
        // 这里应该调用AssetBundleManager的检查方法
        return false;
    }

    /// <summary>
    /// 计算健康度分数
    /// </summary>
    private float CalculateHealthScore(DependencyHealthReport report)
    {
        float score = 100f;
        
        // 扣分项
        score -= report.circularDependencies * 10f;
        score -= report.deepDependencies * 5f;
        score -= report.highCouplingBundles * 3f;
        
        // 问题Bundle比例扣分
        float problemRatio = (float)report.problematicBundles.Count / report.totalBundles;
        score -= problemRatio * 30f;
        
        return Mathf.Clamp(score, 0f, 100f);
    }

    /// <summary>
    /// 预加载常用依赖
    /// </summary>
    private IEnumerator PreloadCommonDependencies()
    {
        Log("开始预加载常用依赖...");
        
        foreach (string dep in commonDependencies)
        {
            if (dependencyGraph.GetNode(dep) != null)
            {
                yield return LoadDependencyAsync(dep);
            }
        }
        
        Log("常用依赖预加载完成");
    }

    /// <summary>
    /// 合并常用依赖
    /// </summary>
    private IEnumerator MergeCommonDependencies(List<string> frequentlyUsedBundles)
    {
        // 分析常用依赖
        Dictionary<string, int> dependencyFrequency = new Dictionary<string, int>();
        
        foreach (string bundle in frequentlyUsedBundles)
        {
            var deps = ResolveDependencies(bundle).dependencies;
            foreach (string dep in deps)
            {
                dependencyFrequency.TryGetValue(dep, out int count);
                dependencyFrequency[dep] = count + 1;
            }
        }
        
        // 找出高频依赖
        var highFrequencyDeps = dependencyFrequency
            .Where(kvp => kvp.Value > frequentlyUsedBundles.Count * 0.3f) // 30%以上的Bundle使用
            .Select(kvp => kvp.Key)
            .ToList();
        
        Log($"找到 {highFrequencyDeps.Count} 个高频依赖");
        
        // 这里可以实现合并逻辑,比如创建共享Bundle
        yield return null;
    }

    /// <summary>
    /// 重构深度依赖
    /// </summary>
    private IEnumerator RefactorDeepDependencies()
    {
        // 找出深度过大的依赖链
        List<string> deepChains = new List<string>();
        
        foreach (var bundle in GetAllNodes())
        {
            int depth = CalculateDependencyDepth(bundle, new HashSet<string>());
            if (depth > 5) // 深度大于5的依赖链
            {
                deepChains.Add(bundle);
            }
        }
        
        Log($"找到 {deepChains.Count} 个深度依赖链");
        
        // 重构逻辑:将深度依赖拆分为多个中间Bundle
        yield return null;
    }

    /// <summary>
    /// 清理无用依赖
    /// </summary>
    private IEnumerator CleanupUnusedDependencies()
    {
        // 找出没有被任何Bundle依赖的叶子节点
        List<string> unusedDeps = new List<string>();
        
        foreach (var bundle in GetAllNodes())
        {
            var dependents = dependencyGraph.GetAllDependents(bundle);
            if (dependents.Count == 0)
            {
                unusedDeps.Add(bundle);
            }
        }
        
        Log($"找到 {unusedDeps.Count} 个无用依赖");
        
        // 清理逻辑:标记或移除无用依赖
        yield return null;
    }

    /// <summary>
    /// 日志输出
    /// </summary>
    private void Log(string message)
    {
        if (enableLog)
            Debug.Log($"[DependencyManager] {message}");
    }

    private void LogWarning(string message)
    {
        Debug.LogWarning($"[DependencyManager] {message}");
    }

    private void LogError(string message)
    {
        Debug.LogError($"[DependencyManager] {message}");
    }
    #endregion

    #region 辅助类

    /// <summary>
    /// 依赖关系解析结果
    /// </summary>
    public class DependencyResult
    {
        public bool success;
        public List<string> dependencies;
        public List<string> directDependencies;
        public string error;
        public int dependencyDepth;
        public bool fromCache;
    }

    /// <summary>
    /// 依赖树节点
    /// </summary>
    public class DependencyTreeNode
    {
        public string bundleName;
        public int depth;
        public List<string> dependencies = new List<string>();
    }

    /// <summary>
    /// 依赖树
    /// </summary>
    public class DependencyTree
    {
        public string rootBundle;
        public List<DependencyTreeNode> nodes;
        
        public void PrintTree()
        {
            foreach (var node in nodes)
            {
                string indent = new string(' ', node.depth * 2);
                Debug.Log($"{indent}{node.bundleName}");
            }
        }
    }

    /// <summary>
    /// 依赖健康度报告
    /// </summary>
    public class DependencyHealthReport
    {
        public int totalBundles;
        public int circularDependencies;
        public int deepDependencies; // 深度超过限制
        public int highCouplingBundles; // 高耦合Bundle
        public List<string> problematicBundles;
        public float healthScore; // 健康度分数 0-100
        public DateTime analyzedAt;
        
        public void PrintReport()
        {
            Debug.Log($"=== 依赖健康度报告 ===");
            Debug.Log($"分析时间: {analyzedAt}");
            Debug.Log($"总Bundle数: {totalBundles}");
            Debug.Log($"循环依赖: {circularDependencies}");
            Debug.Log($"深度依赖: {deepDependencies}");
            Debug.Log($"高耦合Bundle: {highCouplingBundles}");
            Debug.Log($"问题Bundle数: {problematicBundles?.Count ?? 0}");
            Debug.Log($"健康度分数: {healthScore:F1}/100");
            
            if (problematicBundles != null && problematicBundles.Count > 0)
            {
                Debug.Log("问题Bundle列表:");
                foreach (string bundle in problematicBundles)
                {
                    Debug.Log($"  - {bundle}");
                }
            }
        }
    }

    /// <summary>
    /// 依赖统计信息
    /// </summary>
    public class DependencyStats
    {
        public int dependencyResolutions;
        public int cacheHits;
        public int tasksSubmitted;
        public int tasksCompleted;
        public int tasksFailed;
        public DateTime startTime = DateTime.Now;
        
        public TimeSpan Uptime => DateTime.Now - startTime;
        
        public void Reset()
        {
            dependencyResolutions = 0;
            cacheHits = 0;
            tasksSubmitted = 0;
            tasksCompleted = 0;
            tasksFailed = 0;
            startTime = DateTime.Now;
        }
        
        public void PrintStats()
        {
            Debug.Log($"=== 依赖统计信息 ===");
            Debug.Log($"运行时间: {Uptime:hh\\:mm\\:ss}");
            Debug.Log($"依赖解析次数: {dependencyResolutions}");
            Debug.Log($"缓存命中次数: {cacheHits}");
            Debug.Log($"任务提交数: {tasksSubmitted}");
            Debug.Log($"任务完成数: {tasksCompleted}");
            Debug.Log($"任务失败数: {tasksFailed}");
            
            if (dependencyResolutions > 0)
            {
                float hitRate = (float)cacheHits / dependencyResolutions * 100;
                Debug.Log($"缓存命中率: {hitRate:F1}%");
            }
        }
    }

    /// <summary>
    /// 优先级队列
    /// </summary>
    public class PriorityQueue<T>
    {
        private List<T> data;
        private IComparer<T> comparer;
        
        public PriorityQueue(IComparer<T> comparer)
        {
            this.data = new List<T>();
            this.comparer = comparer;
        }
        
        public void Enqueue(T item)
        {
            data.Add(item);
            int i = data.Count - 1;
            
            while (i > 0)
            {
                int parent = (i - 1) / 2;
                if (comparer.Compare(data[i], data[parent]) <= 0)
                    break;
                
                Swap(i, parent);
                i = parent;
            }
        }
        
        public T Dequeue()
        {
            if (data.Count == 0) return default(T);
            
            T frontItem = data[0];
            int lastIndex = data.Count - 1;
            data[0] = data[lastIndex];
            data.RemoveAt(lastIndex);
            
            lastIndex--;
            int parent = 0;
            
            while (true)
            {
                int leftChild = parent * 2 + 1;
                if (leftChild > lastIndex) break;
                
                int rightChild = leftChild + 1;
                int maxChild = leftChild;
                
                if (rightChild <= lastIndex && 
                    comparer.Compare(data[rightChild], data[leftChild]) > 0)
                {
                    maxChild = rightChild;
                }
                
                if (comparer.Compare(data[parent], data[maxChild]) >= 0)
                    break;
                
                Swap(parent, maxChild);
                parent = maxChild;
            }
            
            return frontItem;
        }
        
        public T Peek()
        {
            return data.Count > 0 ? data[0] : default(T);
        }
        
        public int Count => data.Count;
        
        private void Swap(int i, int j)
        {
            T temp = data[i];
            data[i] = data[j];
            data[j] = temp;
        }
    }
    #endregion

    #region Unity生命周期

    void OnApplicationQuit()
    {
        // 保存统计信息
        stats.PrintStats();
        
        // 生成健康度报告
        var report = AnalyzeDependencyHealth();
        report.PrintReport();
    }

    void OnDestroy()
    {
        dependencyGraph.Clear();
        ClearCache();
    }
    #endregion
}

4.2 依赖关系优化策略

csharp

// 1. 共享资源打包策略
public class BundlePackingStrategy
{
    /*
    推荐打包策略:
    - 公共资源(UI字体、通用材质) → common.bundle
    - 场景专用资源 → scene_xxx.bundle
    - 角色模型/动画 → character_xxx.bundle
    - 按需加载的配置表 → config.bundle
    */
    
    // 2. Bundle 粒度控制
    /*
    小Bundle优点:加载快、内存占用小
    大Bundle优点:依赖少、管理简单
    
    推荐方案:
    - 单个Bundle < 10MB
    - 同类型资源打包在一起
    - 频繁更新资源独立打包
    */
}

五、内存管理与卸载

5.1 正确的卸载策略

csharp

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.ResourceManagement.AsyncOperations;

/// <summary>
/// 内存压力级别
/// </summary>
public enum MemoryPressureLevel
{
    Low,        // 低压力
    Normal,     // 正常
    High,       // 高压力
    Critical    // 临界压力
}

/// <summary>
/// 内存清理策略
/// </summary>
public enum MemoryCleanupStrategy
{
    Conservative,   // 保守:只清理无引用的资源
    Aggressive,     // 激进:清理长期未使用的资源
    Custom          // 自定义策略
}

/// <summary>
/// 内存监控配置
/// </summary>
[System.Serializable]
public class MemoryMonitorConfig
{
    [Header("内存阈值配置")]
    [Tooltip("低内存警告阈值(MB)")]
    public float lowMemoryThresholdMB = 300f;
    
    [Tooltip("高内存警告阈值(MB)")]
    public float highMemoryThresholdMB = 500f;
    
    [Tooltip("临界内存阈值(MB)")]
    public float criticalMemoryThresholdMB = 700f;
    
    [Tooltip("目标内存限制(MB)")]
    public float targetMemoryLimitMB = 400f;
    
    [Header("自动清理配置")]
    [Tooltip("自动清理间隔(秒)")]
    public float autoCleanupInterval = 30f;
    
    [Tooltip("未使用资源保留时间(秒)")]
    public float unusedAssetRetentionTime = 60f;
    
    [Tooltip("最小清理间隔(秒)")]
    public float minCleanupInterval = 10f;
    
    [Tooltip("内存压力检测频率(秒)")]
    public float pressureCheckInterval = 5f;
    
    [Header("清理策略")]
    [Tooltip("默认清理策略")]
    public MemoryCleanupStrategy defaultStrategy = MemoryCleanupStrategy.Conservative;
    
    [Tooltip("高压力时自动切换到激进清理")]
    public bool autoSwitchToAggressive = true;
    
    [Header("性能优化")]
    [Tooltip("启用内存碎片整理")]
    public bool enableDefragmentation = true;
    
    [Tooltip("最大同时清理操作数")]
    public int maxConcurrentCleanups = 3;
    
    [Tooltip("帧预算(每帧清理时间限制ms)")]
    public float frameBudgetMS = 5f;
}

/// <summary>
/// 内存资源信息
/// </summary>
[System.Serializable]
public class MemoryResourceInfo
{
    public string resourceId;
    public string bundleName;
    public long memorySize;
    public int referenceCount;
    public DateTime lastAccessTime;
    public DateTime loadTime;
    public bool isPersistent;
    public string resourceType;
    public List<string> references = new List<string>();
    
    [NonSerialized]
    public UnityEngine.Object resourceObject;
    
    public TimeSpan Age => DateTime.Now - loadTime;
    public TimeSpan IdleTime => DateTime.Now - lastAccessTime;
    
    public MemoryResourceInfo(string id, string bundle, UnityEngine.Object obj, long size)
    {
        resourceId = id;
        bundleName = bundle;
        resourceObject = obj;
        memorySize = size;
        loadTime = DateTime.Now;
        lastAccessTime = DateTime.Now;
        referenceCount = 0;
        isPersistent = false;
        resourceType = obj.GetType().Name;
    }
    
    public void AddReference(string reference)
    {
        if (!references.Contains(reference))
        {
            references.Add(reference);
        }
        referenceCount++;
        lastAccessTime = DateTime.Now;
    }
    
    public void RemoveReference(string reference)
    {
        if (references.Contains(reference))
        {
            references.Remove(reference);
        }
        referenceCount = Math.Max(0, referenceCount - 1);
    }
    
    public bool CanUnload(bool force = false)
    {
        if (isPersistent) return false;
        if (force) return true;
        return referenceCount <= 0;
    }
}

/// <summary>
/// 内存使用报告
/// </summary>
[System.Serializable]
public class MemoryUsageReport
{
    public DateTime reportTime;
    public long totalMemoryBytes;
    public long usedMemoryBytes;
    public long freeMemoryBytes;
    public float memoryUsagePercentage;
    public MemoryPressureLevel pressureLevel;
    public int totalResources;
    public int loadedResources;
    public int referencedResources;
    public int leakedResources;
    public List<MemoryLeakInfo> potentialLeaks = new List<MemoryLeakInfo>();
    public MemoryBreakdown breakdown = new MemoryBreakdown();
    
    public string ToFormattedString(bool detailed = false)
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendLine("=== 内存使用报告 ===");
        sb.AppendLine($"报告时间: {reportTime:yyyy-MM-dd HH:mm:ss}");
        sb.AppendLine($"总内存: {totalMemoryBytes / 1024 / 1024:F1}MB");
        sb.AppendLine($"已用内存: {usedMemoryBytes / 1024 / 1024:F1}MB");
        sb.AppendLine($"可用内存: {freeMemoryBytes / 1024 / 1024:F1}MB");
        sb.AppendLine($"使用率: {memoryUsagePercentage:F1}%");
        sb.AppendLine($"压力级别: {pressureLevel}");
        sb.AppendLine($"资源总数: {totalResources}");
        sb.AppendLine($"已加载资源: {loadedResources}");
        sb.AppendLine($"引用资源: {referencedResources}");
        sb.AppendLine($"疑似泄漏: {leakedResources}");
        
        if (detailed)
        {
            sb.AppendLine("\n--- 内存分布 ---");
            sb.AppendLine($"Textures: {breakdown.textureMemory / 1024 / 1024:F1}MB");
            sb.AppendLine($"Meshes: {breakdown.meshMemory / 1024 / 1024:F1}MB");
            sb.AppendLine($"Materials: {breakdown.materialMemory / 1024 / 1024:F1}MB");
            sb.AppendLine($"Animations: {breakdown.animationMemory / 1024 / 1024:F1}MB");
            sb.AppendLine($"AudioClips: {breakdown.audioMemory / 1024 / 1024:F1}MB");
            sb.AppendLine($"AssetBundles: {breakdown.bundleMemory / 1024 / 1024:F1}MB");
            sb.AppendLine($"Other: {breakdown.otherMemory / 1024 / 1024:F1}MB");
            
            if (potentialLeaks.Count > 0)
            {
                sb.AppendLine("\n--- 潜在内存泄漏 ---");
                foreach (var leak in potentialLeaks.Take(10))
                {
                    sb.AppendLine($"  {leak.resourceId} ({leak.resourceType}): {leak.memorySize / 1024:F1}KB, 年龄: {leak.age.TotalSeconds:F0}s");
                }
            }
        }
        
        return sb.ToString();
    }
}

/// <summary>
/// 内存泄漏信息
/// </summary>
[System.Serializable]
public class MemoryLeakInfo
{
    public string resourceId;
    public string resourceType;
    public long memorySize;
    public TimeSpan age;
    public DateTime loadTime;
    public int referenceCount;
    public List<string> referenceChain;
}

/// <summary>
/// 内存分布详情
/// </summary>
[System.Serializable]
public class MemoryBreakdown
{
    public long textureMemory;
    public long meshMemory;
    public long materialMemory;
    public long animationMemory;
    public long audioMemory;
    public long bundleMemory;
    public long otherMemory;
    
    public void Clear()
    {
        textureMemory = 0;
        meshMemory = 0;
        materialMemory = 0;
        animationMemory = 0;
        audioMemory = 0;
        bundleMemory = 0;
        otherMemory = 0;
    }
}

/// <summary>
/// 内存清理任务
/// </summary>
public class MemoryCleanupTask
{
    public string taskId;
    public MemoryCleanupStrategy strategy;
    public float targetMemoryMB;
    public Action<float> onProgress;
    public Action<bool, string> onComplete;
    public List<string> resourcesToUnload = new List<string>();
    public bool isRunning;
    public float progress;
    
    public MemoryCleanupTask(string id)
    {
        taskId = id;
        isRunning = false;
        progress = 0f;
    }
}

/// <summary>
/// 完善的 MemoryManager 类
/// </summary>
public class MemoryManager : MonoBehaviour
{
    #region 单例模式
    private static MemoryManager _instance;
    public static MemoryManager Instance
    {
        get
        {
            if (_instance == null)
            {
                GameObject go = new GameObject("MemoryManager");
                _instance = go.AddComponent<MemoryManager>();
                DontDestroyOnLoad(go);
            }
            return _instance;
        }
    }
    #endregion

    #region 配置参数
    [Header("内存管理配置")]
    [SerializeField] private MemoryMonitorConfig config = new MemoryMonitorConfig();
    
    [Header("调试选项")]
    [SerializeField] private bool enableLogging = true;
    [SerializeField] private bool enableProfiling = true;
    [SerializeField] private bool logMemoryChanges = false;
    [SerializeField] private bool autoGenerateReports = true;
    [SerializeField] private float reportInterval = 60f;
    #endregion

    #region 内部数据结构
    // 资源管理
    private Dictionary<string, MemoryResourceInfo> resourceRegistry = new Dictionary<string, MemoryResourceInfo>();
    private Dictionary<string, List<string>> bundleResources = new Dictionary<string, List<string>>();
    
    // 内存清理
    private Queue<MemoryCleanupTask> cleanupQueue = new Queue<MemoryCleanupTask>();
    private Dictionary<string, MemoryCleanupTask> activeCleanups = new Dictionary<string, MemoryCleanupTask>();
    private MemoryCleanupStrategy currentStrategy;
    
    // 内存监控
    private MemoryPressureLevel currentPressure = MemoryPressureLevel.Low;
    private long peakMemoryUsage = 0;
    private DateTime lastCleanupTime;
    private DateTime lastReportTime;
    private float lastMemoryCheckTime;
    
    // 统计信息
    private MemoryStats stats = new MemoryStats();
    private List<MemoryUsageReport> historicalReports = new List<MemoryUsageReport>();
    
    // 事件系统
    public event Action<MemoryPressureLevel> OnMemoryPressureChanged;
    public event Action<MemoryUsageReport> OnMemoryReportGenerated;
    public event Action<string, long> OnResourceLoaded;
    public event Action<string, long> OnResourceUnloaded;
    public event Action<MemoryCleanupTask> OnCleanupStarted;
    public event Action<MemoryCleanupTask, bool> OnCleanupCompleted;
    #endregion

    #region 公共接口

    /// <summary>
    /// 初始化内存管理器
    /// </summary>
    public void Initialize()
    {
        if (config == null)
        {
            config = new MemoryMonitorConfig();
        }
        
        currentStrategy = config.defaultStrategy;
        lastCleanupTime = DateTime.Now;
        lastReportTime = DateTime.Now;
        lastMemoryCheckTime = Time.time;
        
        // 启动监控协程
        StartCoroutine(MemoryMonitorRoutine());
        StartCoroutine(AutoCleanupRoutine());
        
        if (autoGenerateReports)
        {
            StartCoroutine(AutoReportRoutine());
        }
        
        Log("MemoryManager 初始化完成");
    }

    /// <summary>
    /// 注册资源
    /// </summary>
    public void RegisterResource(string resourceId, string bundleName, UnityEngine.Object resource, long estimatedSize = 0)
    {
        if (string.IsNullOrEmpty(resourceId) || resource == null)
        {
            Debug.LogError($"无效的资源注册: {resourceId}");
            return;
        }
        
        if (resourceRegistry.ContainsKey(resourceId))
        {
            UpdateResourceAccess(resourceId);
            return;
        }
        
        long actualSize = estimatedSize > 0 ? estimatedSize : EstimateMemorySize(resource);
        
        MemoryResourceInfo info = new MemoryResourceInfo(resourceId, bundleName, resource, actualSize);
        resourceRegistry[resourceId] = info;
        
        // 关联到Bundle
        if (!string.IsNullOrEmpty(bundleName))
        {
            if (!bundleResources.ContainsKey(bundleName))
                bundleResources[bundleName] = new List<string>();
            
            if (!bundleResources[bundleName].Contains(resourceId))
                bundleResources[bundleName].Add(resourceId);
        }
        
        stats.totalResourcesRegistered++;
        stats.totalMemoryAllocated += actualSize;
        
        if (logMemoryChanges)
        {
            Log($"资源注册: {resourceId}, 大小: {actualSize / 1024:F1}KB, 类型: {resource.GetType().Name}");
        }
        
        OnResourceLoaded?.Invoke(resourceId, actualSize);
    }

    /// <summary>
    /// 增加资源引用
    /// </summary>
    public void AddResourceReference(string resourceId, string referenceSource)
    {
        if (resourceRegistry.TryGetValue(resourceId, out MemoryResourceInfo info))
        {
            info.AddReference(referenceSource);
            stats.referenceOperations++;
            
            if (logMemoryChanges)
            {
                Log($"增加引用: {resourceId} <- {referenceSource}, 引用数: {info.referenceCount}");
            }
        }
    }

    /// <summary>
    /// 移除资源引用
    /// </summary>
    public void RemoveResourceReference(string resourceId, string referenceSource)
    {
        if (resourceRegistry.TryGetValue(resourceId, out MemoryResourceInfo info))
        {
            info.RemoveReference(referenceSource);
            stats.referenceOperations++;
            
            if (logMemoryChanges && info.referenceCount == 0)
            {
                Log($"资源无引用: {resourceId}, 空闲: {info.IdleTime.TotalSeconds:F1}s");
            }
        }
    }

    /// <summary>
    /// 更新资源访问时间
    /// </summary>
    public void UpdateResourceAccess(string resourceId)
    {
        if (resourceRegistry.TryGetValue(resourceId, out MemoryResourceInfo info))
        {
            info.lastAccessTime = DateTime.Now;
            stats.accessOperations++;
        }
    }

    /// <summary>
    /// 设置资源常驻内存
    /// </summary>
    public void SetResourcePersistent(string resourceId, bool persistent)
    {
        if (resourceRegistry.TryGetValue(resourceId, out MemoryResourceInfo info))
        {
            info.isPersistent = persistent;
            Log($"资源常驻设置: {resourceId} = {persistent}");
        }
    }

    /// <summary>
    /// 卸载单个资源
    /// </summary>
    public bool UnloadResource(string resourceId, bool force = false)
    {
        if (!resourceRegistry.TryGetValue(resourceId, out MemoryResourceInfo info))
        {
            LogWarning($"尝试卸载未注册的资源: {resourceId}");
            return false;
        }
        
        if (!info.CanUnload(force))
        {
            LogWarning($"资源 {resourceId} 仍有引用 ({info.referenceCount}),无法卸载");
            return false;
        }
        
        // 执行卸载
        if (info.resourceObject != null)
        {
            if (info.resourceObject is GameObject gameObject)
            {
                if (gameObject != null)
                    Destroy(gameObject);
            }
            else
            {
                Resources.UnloadAsset(info.resourceObject);
            }
            
            stats.totalMemoryFreed += info.memorySize;
            stats.resourcesUnloaded++;
            
            if (logMemoryChanges)
            {
                Log($"资源卸载: {resourceId}, 释放: {info.memorySize / 1024:F1}KB");
            }
            
            OnResourceUnloaded?.Invoke(resourceId, info.memorySize);
        }
        
        // 清理注册信息
        if (!string.IsNullOrEmpty(info.bundleName) && 
            bundleResources.ContainsKey(info.bundleName))
        {
            bundleResources[info.bundleName].Remove(resourceId);
            if (bundleResources[info.bundleName].Count == 0)
            {
                bundleResources.Remove(info.bundleName);
            }
        }
        
        resourceRegistry.Remove(resourceId);
        return true;
    }

    /// <summary>
    /// 卸载Bundle所有资源
    /// </summary>
    public int UnloadBundleResources(string bundleName, bool force = false)
    {
        if (!bundleResources.TryGetValue(bundleName, out List<string> resources))
        {
            return 0;
        }
        
        int unloadedCount = 0;
        List<string> resourcesToUnload = new List<string>(resources);
        
        foreach (string resourceId in resourcesToUnload)
        {
            if (UnloadResource(resourceId, force))
            {
                unloadedCount++;
            }
        }
        
        Log($"卸载Bundle资源: {bundleName}, 成功: {unloadedCount}/{resourcesToUnload.Count}");
        return unloadedCount;
    }

    /// <summary>
    /// 执行内存清理
    /// </summary>
    public string RequestMemoryCleanup(MemoryCleanupStrategy strategy = MemoryCleanupStrategy.Custom, 
                                      float targetMemoryMB = -1f, 
                                      Action<float> onProgress = null, 
                                      Action<bool, string> onComplete = null)
    {
        string taskId = $"cleanup_{DateTime.Now:HHmmssfff}";
        
        MemoryCleanupTask task = new MemoryCleanupTask(taskId)
        {
            strategy = strategy == MemoryCleanupStrategy.Custom ? currentStrategy : strategy,
            targetMemoryMB = targetMemoryMB > 0 ? targetMemoryMB : config.targetMemoryLimitMB,
            onProgress = onProgress,
            onComplete = onComplete
        };
        
        lock (cleanupQueue)
        {
            cleanupQueue.Enqueue(task);
        }
        
        Log($"内存清理任务提交: {taskId}, 策略: {task.strategy}, 目标: {task.targetMemoryMB}MB");
        return taskId;
    }

    /// <summary>
    /// 强制GC和资源清理
    /// </summary>
    public IEnumerator ForceCleanup(bool unloadAllUnused = true)
    {
        Log("开始强制内存清理...");
        
        yield return StartCoroutine(CleanupUnusedResources(unloadAllUnused));
        
        // 触发GC
        GC.Collect();
        GC.WaitForPendingFinalizers();
        
        // 等待一帧
        yield return null;
        
        Log("强制内存清理完成");
    }

    /// <summary>
    /// 获取内存使用报告
    /// </summary>
    public MemoryUsageReport GetMemoryUsageReport(bool detailed = false)
    {
        MemoryUsageReport report = new MemoryUsageReport
        {
            reportTime = DateTime.Now,
            pressureLevel = currentPressure
        };
        
        // 获取系统内存信息
        long totalMemory = SystemInfo.systemMemorySize * 1024L * 1024L;
        long usedMemory = Profiler.GetTotalAllocatedMemoryLong();
        long freeMemory = totalMemory - usedMemory;
        
        report.totalMemoryBytes = totalMemory;
        report.usedMemoryBytes = usedMemory;
        report.freeMemoryBytes = freeMemory;
        report.memoryUsagePercentage = totalMemory > 0 ? (float)usedMemory / totalMemory * 100 : 0;
        
        // 统计资源信息
        report.totalResources = resourceRegistry.Count;
        report.loadedResources = resourceRegistry.Count;
        report.referencedResources = resourceRegistry.Values.Count(r => r.referenceCount > 0);
        
        // 分析内存分布
        AnalyzeMemoryBreakdown(report.breakdown);
        
        // 检测潜在内存泄漏
        DetectPotentialLeaks(report);
        
        // 更新峰值内存
        if (usedMemory > peakMemoryUsage)
        {
            peakMemoryUsage = usedMemory;
        }
        
        // 添加到历史记录
        historicalReports.Add(report);
        
        // 触发事件
        OnMemoryReportGenerated?.Invoke(report);
        
        return report;
    }

    /// <summary>
    /// 获取资源信息
    /// </summary>
    public MemoryResourceInfo GetResourceInfo(string resourceId)
    {
        resourceRegistry.TryGetValue(resourceId, out MemoryResourceInfo info);
        return info;
    }

    /// <summary>
    /// 获取Bundle资源列表
    /// </summary>
    public List<string> GetBundleResources(string bundleName)
    {
        if (bundleResources.TryGetValue(bundleName, out List<string> resources))
        {
            return new List<string>(resources);
        }
        return new List<string>();
    }

    /// <summary>
    /// 获取所有资源ID
    /// </summary>
    public List<string> GetAllResourceIds()
    {
        return new List<string>(resourceRegistry.Keys);
    }

    /// <summary>
    /// 检查内存压力
    /// </summary>
    public MemoryPressureLevel CheckMemoryPressure()
    {
        long usedMemoryMB = Profiler.GetTotalAllocatedMemoryLong() / 1024 / 1024;
        
        if (usedMemoryMB >= config.criticalMemoryThresholdMB)
        {
            return MemoryPressureLevel.Critical;
        }
        else if (usedMemoryMB >= config.highMemoryThresholdMB)
        {
            return MemoryPressureLevel.High;
        }
        else if (usedMemoryMB >= config.lowMemoryThresholdMB)
        {
            return MemoryPressureLevel.Normal;
        }
        else
        {
            return MemoryPressureLevel.Low;
        }
    }

    /// <summary>
    /// 更改清理策略
    /// </summary>
    public void SetCleanupStrategy(MemoryCleanupStrategy strategy)
    {
        currentStrategy = strategy;
        Log($"清理策略更改为: {strategy}");
    }

    /// <summary>
    /// 获取统计信息
    /// </summary>
    public MemoryStats GetStats()
    {
        return stats;
    }

    /// <summary>
    /// 重置统计信息
    /// </summary>
    public void ResetStats()
    {
        stats = new MemoryStats();
        Log("统计信息已重置");
    }

    /// <summary>
    /// 导出内存报告
    /// </summary>
    public string ExportMemoryReport(bool includeHistory = false)
    {
        StringBuilder sb = new StringBuilder();
        
        // 当前报告
        var currentReport = GetMemoryUsageReport(true);
        sb.AppendLine(currentReport.ToFormattedString(true));
        
        // 统计信息
        sb.AppendLine("\n=== 内存统计信息 ===");
        sb.AppendLine($"峰值内存使用: {peakMemoryUsage / 1024 / 1024:F1}MB");
        sb.AppendLine($"总注册资源数: {stats.totalResourcesRegistered}");
        sb.AppendLine($"总卸载资源数: {stats.resourcesUnloaded}");
        sb.AppendLine($"总分配内存: {stats.totalMemoryAllocated / 1024 / 1024:F1}MB");
        sb.AppendLine($"总释放内存: {stats.totalMemoryFreed / 1024 / 1024:F1}MB");
        sb.AppendLine($"引用操作次数: {stats.referenceOperations}");
        sb.AppendLine($"访问操作次数: {stats.accessOperations}");
        sb.AppendLine($"自动清理次数: {stats.autoCleanupsPerformed}");
        sb.AppendLine($"内存警告次数: {stats.memoryWarnings}");
        
        // 历史报告(如果需要)
        if (includeHistory && historicalReports.Count > 0)
        {
            sb.AppendLine("\n=== 历史报告摘要 ===");
            int count = Mathf.Min(5, historicalReports.Count);
            for (int i = historicalReports.Count - count; i < historicalReports.Count; i++)
            {
                var report = historicalReports[i];
                sb.AppendLine($"[{report.reportTime:HH:mm:ss}] {report.memoryUsagePercentage:F1}%, {report.pressureLevel}");
            }
        }
        
        // 资源详情(前20个最大的资源)
        sb.AppendLine("\n=== 最大内存资源(前20) ===");
        var topResources = resourceRegistry.Values
            .OrderByDescending(r => r.memorySize)
            .Take(20)
            .ToList();
        
        foreach (var resource in topResources)
        {
            sb.AppendLine($"  {resource.resourceId}: {resource.memorySize / 1024:F1}KB, " +
                         $"引用: {resource.referenceCount}, " +
                         $"年龄: {resource.Age.TotalMinutes:F0}m, " +
                         $"类型: {resource.resourceType}");
        }
        
        return sb.ToString();
    }

    /// <summary>
    /// 优化内存使用
    /// </summary>
    public IEnumerator OptimizeMemoryUsage()
    {
        Log("开始内存优化...");
        
        // 1. 卸载长期未使用的资源
        yield return StartCoroutine(CleanupIdleResources());
        
        // 2. 整理内存碎片
        if (config.enableDefragmentation)
        {
            yield return StartCoroutine(DefragmentMemory());
        }
        
        // 3. 压缩纹理(如果支持)
        yield return StartCoroutine(CompressTextures());
        
        // 4. 清理AssetBundle缓存
        yield return StartCoroutine(CleanupAssetBundleCache());
        
        Log("内存优化完成");
    }
    #endregion

    #region 内部实现

    /// <summary>
    /// 内存监控协程
    /// </summary>
    private IEnumerator MemoryMonitorRoutine()
    {
        while (true)
        {
            yield return new WaitForSeconds(config.pressureCheckInterval);
            
            // 检查内存压力
            MemoryPressureLevel newPressure = CheckMemoryPressure();
            
            if (newPressure != currentPressure)
            {
                currentPressure = newPressure;
                OnMemoryPressureChanged?.Invoke(currentPressure);
                
                Log($"内存压力级别变化: {currentPressure}");
                
                // 高压力时自动切换清理策略
                if (config.autoSwitchToAggressive && 
                    currentPressure >= MemoryPressureLevel.High)
                {
                    SetCleanupStrategy(MemoryCleanupStrategy.Aggressive);
                    
                    // 自动触发清理
                    RequestMemoryCleanup(MemoryCleanupStrategy.Aggressive);
                }
                
                if (currentPressure >= MemoryPressureLevel.High)
                {
                    stats.memoryWarnings++;
                }
            }
            
            // 记录内存峰值
            long currentMemory = Profiler.GetTotalAllocatedMemoryLong();
            if (currentMemory > peakMemoryUsage)
            {
                peakMemoryUsage = currentMemory;
            }
        }
    }

    /// <summary>
    /// 自动清理协程
    /// </summary>
    private IEnumerator AutoCleanupRoutine()
    {
        while (true)
        {
            yield return new WaitForSeconds(config.autoCleanupInterval);
            
            // 检查是否需要清理
            if (ShouldPerformAutoCleanup())
            {
                Log("执行自动内存清理...");
                
                string taskId = RequestMemoryCleanup(currentStrategy, 
                    onComplete: (success, message) => {
                        if (success)
                        {
                            stats.autoCleanupsPerformed++;
                            Log($"自动清理完成: {message}");
                        }
                    });
                
                lastCleanupTime = DateTime.Now;
            }
            
            // 处理清理队列
            yield return StartCoroutine(ProcessCleanupQueue());
        }
    }

    /// <summary>
    /// 自动报告协程
    /// </summary>
    private IEnumerator AutoReportRoutine()
    {
        while (true)
        {
            yield return new WaitForSeconds(reportInterval);
            
            if (currentPressure >= MemoryPressureLevel.High || 
                (DateTime.Now - lastReportTime).TotalMinutes >= 5)
            {
                var report = GetMemoryUsageReport();
                Log(report.ToFormattedString(false));
                lastReportTime = DateTime.Now;
            }
        }
    }

    /// <summary>
    /// 处理清理队列
    /// </summary>
    private IEnumerator ProcessCleanupQueue()
    {
        while (cleanupQueue.Count > 0 && activeCleanups.Count < config.maxConcurrentCleanups)
        {
            MemoryCleanupTask task;
            lock (cleanupQueue)
            {
                task = cleanupQueue.Dequeue();
            }
            
            activeCleanups[task.taskId] = task;
            StartCoroutine(ExecuteCleanupTask(task));
            
            yield return null;
        }
    }

    /// <summary>
    /// 执行清理任务
    /// </summary>
    private IEnumerator ExecuteCleanupTask(MemoryCleanupTask task)
    {
        task.isRunning = true;
        OnCleanupStarted?.Invoke(task);
        
        Log($"开始执行清理任务: {task.taskId}");
        
        try
        {
            // 根据策略选择资源卸载
            SelectResourcesForCleanup(task);
            
            int totalResources = task.resourcesToUnload.Count;
            int unloadedCount = 0;
            
            task.progress = 0f;
            task.onProgress?.Invoke(0f);
            
            // 分批卸载资源,避免卡顿
            for (int i = 0; i < totalResources; i++)
            {
                string resourceId = task.resourcesToUnload[i];
                
                if (UnloadResource(resourceId, false))
                {
                    unloadedCount++;
                }
                
                // 更新进度
                task.progress = (float)(i + 1) / totalResources;
                task.onProgress?.Invoke(task.progress);
                
                // 每卸载10个资源检查一次帧时间
                if (i % 10 == 0)
                {
                    yield return null;
                }
            }
            
            // 执行GC
            yield return StartCoroutine(CleanupUnusedResources(false));
            
            // 检查是否达到目标
            bool success = CheckCleanupSuccess(task);
            string message = $"清理完成: {unloadedCount}/{totalResources} 个资源已卸载";
            
            task.onComplete?.Invoke(success, message);
            OnCleanupCompleted?.Invoke(task, success);
            
            Log($"清理任务完成: {task.taskId}, {message}");
        }
        catch (Exception e)
        {
            string error = $"清理任务失败: {e.Message}";
            task.onComplete?.Invoke(false, error);
            OnCleanupCompleted?.Invoke(task, false);
            LogError(error);
        }
        finally
        {
            task.isRunning = false;
            activeCleanups.Remove(task.taskId);
        }
    }

    /// <summary>
    /// 选择需要清理的资源
    /// </summary>
    private void SelectResourcesForCleanup(MemoryCleanupTask task)
    {
        task.resourcesToUnload.Clear();
        
        List<MemoryResourceInfo> candidates = new List<MemoryResourceInfo>();
        
        foreach (var kvp in resourceRegistry)
        {
            MemoryResourceInfo info = kvp.Value;
            
            // 跳过常驻资源
            if (info.isPersistent)
                continue;
            
            // 根据策略筛选
            switch (task.strategy)
            {
                case MemoryCleanupStrategy.Conservative:
                    // 只清理无引用的资源
                    if (info.referenceCount <= 0)
                    {
                        candidates.Add(info);
                    }
                    break;
                    
                case MemoryCleanupStrategy.Aggressive:
                    // 清理长期未使用的资源,即使有引用
                    if (info.IdleTime.TotalSeconds > config.unusedAssetRetentionTime * 2)
                    {
                        candidates.Add(info);
                    }
                    else if (info.referenceCount <= 0)
                    {
                        candidates.Add(info);
                    }
                    break;
            }
        }
        
        // 排序:按最后访问时间(最旧优先)或内存大小(最大优先)
        if (task.strategy == MemoryCleanupStrategy.Aggressive)
        {
            candidates.Sort((a, b) => {
                // 优先清理无引用的
                if (a.referenceCount == 0 && b.referenceCount > 0) return -1;
                if (a.referenceCount > 0 && b.referenceCount == 0) return 1;
                
                // 然后按内存大小降序
                return b.memorySize.CompareTo(a.memorySize);
            });
        }
        else
        {
            candidates.Sort((a, b) => a.lastAccessTime.CompareTo(b.lastAccessTime));
        }
        
        // 选择资源直到达到目标内存或选择所有候选
        long targetMemoryBytes = (long)(task.targetMemoryMB * 1024 * 1024);
        long currentMemory = Profiler.GetTotalAllocatedMemoryLong();
        long memoryToFree = currentMemory - targetMemoryBytes;
        
        if (memoryToFree > 0)
        {
            long freedMemory = 0;
            
            foreach (var info in candidates)
            {
                if (freedMemory >= memoryToFree)
                    break;
                    
                task.resourcesToUnload.Add(info.resourceId);
                freedMemory += info.memorySize;
            }
        }
        else
        {
            // 如果不需要释放内存,仍然清理一些最旧的无引用资源
            foreach (var info in candidates)
            {
                if (info.referenceCount <= 0 && 
                    info.IdleTime.TotalSeconds > config.unusedAssetRetentionTime)
                {
                    task.resourcesToUnload.Add(info.resourceId);
                    
                    // 最多清理10个
                    if (task.resourcesToUnload.Count >= 10)
                        break;
                }
            }
        }
    }

    /// <summary>
    /// 检查清理是否成功
    /// </summary>
    private bool CheckCleanupSuccess(MemoryCleanupTask task)
    {
        long currentMemoryMB = Profiler.GetTotalAllocatedMemoryLong() / 1024 / 1024;
        
        if (task.targetMemoryMB > 0)
        {
            return currentMemoryMB <= task.targetMemoryMB;
        }
        
        return task.resourcesToUnload.Count > 0;
    }

    /// <summary>
    /// 清理未使用的资源
    /// </summary>
    private IEnumerator CleanupUnusedResources(bool unloadAll)
    {
        AsyncOperation asyncOp = Resources.UnloadUnusedAssets();
        
        while (!asyncOp.isDone)
        {
            yield return null;
        }
        
        if (unloadAll)
        {
            // 强制GC
            GC.Collect();
            yield return null;
        }
    }

    /// <summary>
    /// 清理空闲资源
    /// </summary>
    private IEnumerator CleanupIdleResources()
    {
        List<string> idleResources = new List<string>();
        
        foreach (var kvp in resourceRegistry)
        {
            MemoryResourceInfo info = kvp.Value;
            
            if (!info.isPersistent && 
                info.referenceCount <= 0 && 
                info.IdleTime.TotalSeconds > config.unusedAssetRetentionTime)
            {
                idleResources.Add(kvp.Key);
            }
        }
        
        int unloaded = 0;
        foreach (string resourceId in idleResources)
        {
            if (UnloadResource(resourceId, false))
            {
                unloaded++;
                
                if (unloaded % 5 == 0)
                {
                    yield return null;
                }
            }
        }
        
        if (unloaded > 0)
        {
            Log($"清理空闲资源: {unloaded} 个资源已卸载");
        }
    }

    /// <summary>
    /// 内存碎片整理
    /// </summary>
    private IEnumerator DefragmentMemory()
    {
        Log("开始内存碎片整理...");
        
        // 1. 卸载所有非必要资源
        yield return StartCoroutine(CleanupIdleResources());
        
        // 2. 触发GC
        GC.Collect();
        GC.WaitForPendingFinalizers();
        
        // 3. 等待几帧让内存稳定
        for (int i = 0; i < 3; i++)
        {
            yield return null;
        }
        
        Log("内存碎片整理完成");
    }

    /// <summary>
    /// 压缩纹理(如果支持)
    /// </summary>
    private IEnumerator CompressTextures()
    {
        // 这里可以实现纹理压缩逻辑
        // 注意:纹理压缩可能会影响性能,需要谨慎使用
        
        yield return null;
    }

    /// <summary>
    /// 清理AssetBundle缓存
    /// </summary>
    private IEnumerator CleanupAssetBundleCache()
    {
        // 清理未使用的AssetBundle
        Caching.ClearCache();
        
        yield return null;
        
        Log("AssetBundle缓存已清理");
    }

    /// <summary>
    /// 分析内存分布
    /// </summary>
    private void AnalyzeMemoryBreakdown(MemoryBreakdown breakdown)
    {
        breakdown.Clear();
        
        foreach (var info in resourceRegistry.Values)
        {
            switch (info.resourceType)
            {
                case "Texture2D":
                case "Texture":
                    breakdown.textureMemory += info.memorySize;
                    break;
                    
                case "Mesh":
                    breakdown.meshMemory += info.memorySize;
                    break;
                    
                case "Material":
                    breakdown.materialMemory += info.memorySize;
                    break;
                    
                case "AnimationClip":
                    breakdown.animationMemory += info.memorySize;
                    break;
                    
                case "AudioClip":
                    breakdown.audioMemory += info.memorySize;
                    break;
                    
                case "AssetBundle":
                    breakdown.bundleMemory += info.memorySize;
                    break;
                    
                default:
                    breakdown.otherMemory += info.memorySize;
                    break;
            }
        }
    }

    /// <summary>
    /// 检测潜在内存泄漏
    /// </summary>
    private void DetectPotentialLeaks(MemoryUsageReport report)
    {
        report.potentialLeaks.Clear();
        
        foreach (var info in resourceRegistry.Values)
        {
            // 检测标准:无引用但长期未卸载
            if (info.referenceCount <= 0 && info.Age.TotalSeconds > config.unusedAssetRetentionTime * 3)
            {
                var leak = new MemoryLeakInfo
                {
                    resourceId = info.resourceId,
                    resourceType = info.resourceType,
                    memorySize = info.memorySize,
                    age = info.Age,
                    loadTime = info.loadTime,
                    referenceCount = info.referenceCount,
                    referenceChain = new List<string>(info.references)
                };
                
                report.potentialLeaks.Add(leak);
                report.leakedResources++;
            }
        }
    }

    /// <summary>
    /// 估计资源内存大小
    /// </summary>
    private long EstimateMemorySize(UnityEngine.Object obj)
    {
        if (obj == null) return 0;
        
        try
        {
            if (obj is Texture2D texture)
            {
                return texture.width * texture.height * 4; // 假设RGBA32格式
            }
            else if (obj is Mesh mesh)
            {
                int vertexSize = mesh.vertexCount * 12; // Vector3 = 12 bytes
                int triangleSize = mesh.triangles.Length * 4; // int = 4 bytes
                return vertexSize + triangleSize;
            }
            else if (obj is AudioClip audioClip)
            {
                return (long)(audioClip.length * audioClip.frequency * 2 * audioClip.channels);
            }
            else if (obj is GameObject gameObject)
            {
                // 估算GameObject的内存比较复杂,这里返回一个基础值
                return 1024; // 1KB基础值
            }
            else
            {
                // 其他类型的基础估计
                return 512;
            }
        }
        catch
        {
            return 1024; // 默认1KB
        }
    }

    /// <summary>
    /// 检查是否应该执行自动清理
    /// </summary>
    private bool ShouldPerformAutoCleanup()
    {
        // 检查时间间隔
        if ((DateTime.Now - lastCleanupTime).TotalSeconds < config.minCleanupInterval)
            return false;
        
        // 检查内存压力
        MemoryPressureLevel pressure = CheckMemoryPressure();
        
        // 高压力时总是清理
        if (pressure >= MemoryPressureLevel.High)
            return true;
        
        // 正常压力时按概率清理
        if (pressure == MemoryPressureLevel.Normal)
        {
            float memoryUsage = (float)Profiler.GetTotalAllocatedMemoryLong() / 
                               (config.highMemoryThresholdMB * 1024 * 1024);
            
            // 内存使用率越高,清理概率越大
            float cleanupProbability = Mathf.Clamp01(memoryUsage - 0.5f) * 0.5f;
            return UnityEngine.Random.value < cleanupProbability;
        }
        
        return false;
    }

    /// <summary>
    /// 日志输出
    /// </summary>
    private void Log(string message)
    {
        if (enableLogging)
            Debug.Log($"[MemoryManager] {message}");
    }

    private void LogWarning(string message)
    {
        Debug.LogWarning($"[MemoryManager] {message}");
    }

    private void LogError(string message)
    {
        Debug.LogError($"[MemoryManager] {message}");
    }
    #endregion

    #region 辅助类

    /// <summary>
    /// 内存统计信息
    /// </summary>
    [System.Serializable]
    public class MemoryStats
    {
        public int totalResourcesRegistered;
        public int resourcesUnloaded;
        public long totalMemoryAllocated;
        public long totalMemoryFreed;
        public int referenceOperations;
        public int accessOperations;
        public int autoCleanupsPerformed;
        public int memoryWarnings;
        public DateTime startTime = DateTime.Now;
        
        public TimeSpan Uptime => DateTime.Now - startTime;
        
        public void Reset()
        {
            totalResourcesRegistered = 0;
            resourcesUnloaded = 0;
            totalMemoryAllocated = 0;
            totalMemoryFreed = 0;
            referenceOperations = 0;
            accessOperations = 0;
            autoCleanupsPerformed = 0;
            memoryWarnings = 0;
            startTime = DateTime.Now;
        }
        
        public void PrintStats()
        {
            Debug.Log($"=== 内存统计 ===");
            Debug.Log($"运行时间: {Uptime:hh\\:mm\\:ss}");
            Debug.Log($"注册资源: {totalResourcesRegistered}");
            Debug.Log($"卸载资源: {resourcesUnloaded}");
            Debug.Log($"分配内存: {totalMemoryAllocated / 1024 / 1024:F1}MB");
            Debug.Log($"释放内存: {totalMemoryFreed / 1024 / 1024:F1}MB");
            Debug.Log($"净内存: {(totalMemoryAllocated - totalMemoryFreed) / 1024 / 1024:F1}MB");
            Debug.Log($"引用操作: {referenceOperations}");
            Debug.Log($"访问操作: {accessOperations}");
            Debug.Log($"自动清理: {autoCleanupsPerformed}");
            Debug.Log($"内存警告: {memoryWarnings}");
        }
    }
    #endregion

    #region Unity生命周期

    void OnEnable()
    {
        Initialize();
    }

    void OnDisable()
    {
        StopAllCoroutines();
    }

    void OnApplicationQuit()
    {
        // 生成最终报告
        string finalReport = ExportMemoryReport(true);
        Debug.Log(finalReport);
        
        // 强制清理所有资源
        StartCoroutine(ForceCleanup(true));
    }

    void OnApplicationPause(bool pauseStatus)
    {
        if (pauseStatus)
        {
            // 应用暂停时执行轻度清理
            RequestMemoryCleanup(MemoryCleanupStrategy.Conservative);
        }
    }

    void OnGUI()
    {
        if (enableProfiling && currentPressure >= MemoryPressureLevel.Normal)
        {
            DrawMemoryInfo();
        }
    }

    /// <summary>
    /// 在屏幕上绘制内存信息
    /// </summary>
    private void DrawMemoryInfo()
    {
        GUI.color = GetPressureColor(currentPressure);
        GUI.backgroundColor = new Color(0, 0, 0, 0.7f);
        
        GUILayout.BeginArea(new Rect(10, 10, 300, 150));
        GUILayout.BeginVertical("Box");
        
        long totalMB = Profiler.GetTotalAllocatedMemoryLong() / 1024 / 1024;
        long reservedMB = Profiler.GetTotalReservedMemoryLong() / 1024 / 1024;
        
        GUILayout.Label($"内存状态: {currentPressure}");
        GUILayout.Label($"已用内存: {totalMB}MB");
        GUILayout.Label($"保留内存: {reservedMB}MB");
        GUILayout.Label($"资源数量: {resourceRegistry.Count}");
        GUILayout.Label($"峰值内存: {peakMemoryUsage / 1024 / 1024}MB");
        
        // 显示压力级别指示器
        GUILayout.BeginHorizontal();
        for (int i = 0; i < 4; i++)
        {
            GUI.color = i <= (int)currentPressure ? Color.red : Color.gray;
            GUILayout.Box("", GUILayout.Width(20), GUILayout.Height(10));
        }
        GUILayout.EndHorizontal();
        
        GUILayout.EndVertical();
        GUILayout.EndArea();
        
        GUI.color = Color.white;
    }

    private Color GetPressureColor(MemoryPressureLevel level)
    {
        switch (level)
        {
            case MemoryPressureLevel.Low: return Color.green;
            case MemoryPressureLevel.Normal: return Color.yellow;
            case MemoryPressureLevel.High: return new Color(1, 0.5f, 0); // 橙色
            case MemoryPressureLevel.Critical: return Color.red;
            default: return Color.white;
        }
    }
    #endregion
}

5.2 卸载策略对比

卸载方法参数效果适用场景
Unload(false)false只卸载AssetBundle文件,保留已实例化的资源资源正在使用,后续可能还要加载同一Bundle
Unload(true)true卸载AssetBundle和所有加载的资源确定不再需要该Bundle的任何资源
Resources.UnloadUnusedAssets()-卸载所有未引用的资源场景切换、内存紧张时
Resources.UnloadAsset()具体资源卸载指定资源精确控制单个资源卸载

六、热更新实现方案

6.1 热更新流程

csharp

public class HotUpdateManager : MonoBehaviour
{
    private string serverURL = "http://your-server.com/assetbundles/";
    private string localPath;
    private Hash128 remoteHash;
    
    void Start()
    {
        localPath = Application.persistentDataPath + "/AssetBundles/";
        StartCoroutine(CheckForUpdates());
    }
    
    IEnumerator CheckForUpdates()
    {
        // 1. 下载版本文件
        string versionURL = serverURL + "version.json";
        using (UnityWebRequest versionRequest = UnityWebRequest.Get(versionURL))
        {
            yield return versionRequest.SendWebRequest();
            
            if (versionRequest.result == UnityWebRequest.Result.Success)
            {
                VersionInfo remoteVersion = JsonUtility.FromJson<VersionInfo>(
                    versionRequest.downloadHandler.text
                );
                
                // 2. 比较版本
                VersionInfo localVersion = LoadLocalVersion();
                
                if (remoteVersion.version > localVersion.version)
                {
                    // 3. 下载更新
                    yield return DownloadUpdates(remoteVersion);
                }
            }
        }
    }
    
    IEnumerator DownloadUpdates(VersionInfo remoteVersion)
    {
        // 4. 下载差异文件
        foreach (BundleInfo bundle in remoteVersion.bundles)
        {
            string localFile = localPath + bundle.name;
            string remoteFile = serverURL + bundle.name;
            
            // 检查本地文件是否存在且哈希匹配
            if (File.Exists(localFile))
            {
                Hash128 localHash = Hash128.Parse(
                    File.ReadAllText(localFile + ".hash")
                );
                
                if (localHash == bundle.hash)
                    continue; // 跳过已更新的文件
            }
            
            // 下载更新
            using (UnityWebRequest request = 
                UnityWebRequestAssetBundle.GetAssetBundle(remoteFile, bundle.hash))
            {
                yield return request.SendWebRequest();
                
                if (request.result == UnityWebRequest.Result.Success)
                {
                    // 保存到本地
                    byte[] data = request.downloadHandler.data;
                    File.WriteAllBytes(localFile, data);
                    File.WriteAllText(localFile + ".hash", bundle.hash.ToString());
                }
            }
        }
    }
    
    [System.Serializable]
    public class VersionInfo
    {
        public int version;
        public List<BundleInfo> bundles;
    }
    
    [System.Serializable]
    public class BundleInfo
    {
        public string name;
        public string hash;
        public long size;
    }
}

七、性能优化建议

7.1 加载优化

csharp

public class PerformanceOptimizer
{
    // 1. 预加载常用资源
    public IEnumerator PreloadEssentialBundles()
    {
        string[] essentialBundles = { "common", "ui", "config" };
        
        foreach (string bundle in essentialBundles)
        {
            yield return AssetBundle.LoadFromFileAsync(
                GetBundlePath(bundle)
            );
        }
    }
    
    // 2. 分批加载
    public IEnumerator LoadInBatches(List<string> bundles, int batchSize = 3)
    {
        for (int i = 0; i < bundles.Count; i += batchSize)
        {
            List<IEnumerator> batchLoaders = new List<IEnumerator>();
            
            for (int j = 0; j < batchSize && i + j < bundles.Count; j++)
            {
                batchLoaders.Add(LoadSingleBundle(bundles[i + j]));
            }
            
            // 并行加载一批
            yield return StartCoroutine(ParallelCoroutines(batchLoaders));
            
            // 给一帧休息时间
            yield return null;
        }
    }
    
    // 3. 使用对象池减少重复加载
    public class AssetPool
    {
        private Dictionary<string, Queue<GameObject>> pool = 
            new Dictionary<string, Queue<GameObject>>();
        
        public GameObject GetAsset(string bundleName, string assetName)
        {
            string key = $"{bundleName}/{assetName}";
            
            if (pool.TryGetValue(key, out Queue<GameObject> queue) && queue.Count > 0)
            {
                return queue.Dequeue();
            }
            
            // 从AssetBundle加载
            return LoadNewAsset(bundleName, assetName);
        }
        
        public void ReturnAsset(string bundleName, string assetName, GameObject obj)
        {
            string key = $"{bundleName}/{assetName}";
            
            if (!pool.ContainsKey(key))
                pool[key] = new Queue<GameObject>();
            
            obj.SetActive(false);
            pool[key].Enqueue(obj);
        }
    }
}

7.2 监控与调试

csharp

public class AssetBundleMonitor : MonoBehaviour
{
    void OnGUI()
    {
        GUILayout.BeginArea(new Rect(10, 10, 300, 200));
        
        // 显示已加载的Bundle
        GUILayout.Label("=== 已加载 AssetBundle ===");
        foreach (var bundle in AssetBundle.GetAllLoadedAssetBundles())
        {
            GUILayout.Label($"- {bundle.name}");
        }
        
        // 显示内存使用
        GUILayout.Label($"\n总内存: {Profiler.GetTotalAllocatedMemoryLong() / 1024 / 1024}MB");
        GUILayout.Label($"纹理内存: {Profiler.GetAllocatedMemoryForGraphicsDriver() / 1024 / 1024}MB");
        
        GUILayout.EndArea();
    }
    
    // 记录加载时间
    public class TimedLoader
    {
        private System.Diagnostics.Stopwatch stopwatch = 
            new System.Diagnostics.Stopwatch();
        
        public IEnumerator LoadWithTiming(string bundleName)
        {
            stopwatch.Restart();
            
            AssetBundleCreateRequest request = 
                AssetBundle.LoadFromFileAsync(GetBundlePath(bundleName));
            yield return request;
            
            stopwatch.Stop();
            
            Debug.Log($"{bundleName} 加载耗时: {stopwatch.ElapsedMilliseconds}ms");
        }
    }
}

八、常见问题与解决方案

8.1 问题排查清单

csharp

public class ProblemSolver
{
    /*
    常见问题及解决方案:
    
    1. Bundle加载失败
       - 检查路径是否正确
       - 检查文件名大小写
       - 检查平台是否匹配
    
    2. 依赖丢失
       - 确保所有依赖Bundle已加载
       - 检查Manifest是否正确
    
    3. 内存泄漏
       - 检查Unload调用
       - 使用Profiler分析内存
       - 确保引用计数正确
    
    4. 加载卡顿
       - 使用异步加载
       - 分批加载大资源
       - 预加载常用资源
    
    5. 更新失败
       - 检查网络权限
       - 检查存储空间
       - 验证文件完整性(CRC/MD5)
    */
    
    // 完整性检查
    public bool ValidateBundle(string path, string expectedHash)
    {
        if (!File.Exists(path))
            return false;
        
        using (var md5 = System.Security.Cryptography.MD5.Create())
        {
            using (var stream = File.OpenRead(path))
            {
                byte[] hash = md5.ComputeHash(stream);
                string actualHash = BitConverter.ToString(hash).Replace("-", "").ToLower();
                
                return actualHash == expectedHash.ToLower();
            }
        }
    }
}

总结

最佳实践要点:

  1. 合理规划 Bundle:按功能模块、使用频率划分

  2. 异步加载:避免主线程卡顿

  3. 依赖管理:确保先加载依赖资源

  4. 内存管理:及时卸载不再使用的资源

  5. 版本控制:实现可靠的热更新机制

  6. 错误处理:网络异常、文件损坏等情况的处理

  7. 性能监控:添加加载时间、内存使用监控

推荐的工作流:

  1. 开发阶段:使用 Addressables 或直接 Resources

  2. 发布阶段:转换为 AssetBundle

  3. 更新阶段:通过热更新系统增量更新

  4. 运行阶段:按需加载 + 缓存管理

通过合理的 AssetBundle 管理,可以显著提升游戏性能,降低内存占用,并实现灵活的资源更新策略。

在自媒体领域,内容生产效率作品专业水准日益成为从业者的核心关切。近期推出的Coze工作流集成方案,为内容生产者构建了一套系统化、模块化的创作支持体系。该方案通过预先设计的流程模块,贯穿选题构思、素材整理、文本撰写、视觉编排及渠道分发的完整周期,显著增强了自媒体工作的规范性产出速率。 经过多轮实践验证,这些标准化流程不仅精简了操作步骤,减少了机械性任务的比重,还借助统一的操作框架有效控制了人为失误。由此,创作者得以将主要资源集中于内容创新深度拓展,而非消耗于日常执行事务。具体而言,在选题环节,系统依据实时舆情数据受众偏好模型生成热点建议,辅助快速定位创作方向;在编辑阶段,则提供多套经过验证的版式方案视觉组件,保障内容呈现兼具美学价值阅读流畅性。 分发推广模块同样经过周密设计,整合了跨平台传播策略效果监测工具,涵盖社交网络运营、搜索排序优化、定向推送等多重手段,旨在帮助内容突破单一渠道局限,实现更广泛的受众触达。 该集成方案在提供成熟模板的同时,保留了充分的定制空间,允许用户根据自身创作特性阶段目标调整流程细节。这种“框架统一、细节可变”的设计哲学,兼顾了行业通用标准个体工作习惯,提升了工具在不同应用场景中的适应性。 从行业视角观察,此方案的问世恰逢其时,回应了自媒体专业化进程中对于流程优化工具的迫切需求。其价值不仅体现在即时的效率提升,更在于构建了一个可持续迭代的创作支持生态。通过持续吸纳用户反馈行业趋势,系统将不断演进,助力从业者保持行业发展同步,实现创作质量运营效能的双重进阶。 总体而言,这一工作流集成方案的引入,标志着自媒体创作方法向系统化、精细化方向的重要转变。它在提升作业效率的同时,通过结构化的工作方法强化了内容产出的专业度可持续性,为从业者的职业化发展提供了坚实的方法论基础。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值