当前位置:   article > 正文

AssetBundle资源管理,第三步引用计数的方式管理ab包资源--unity学习_unity的assetbundle引用计数管理

unity的assetbundle引用计数管理

在游戏中会存在大量的ab包资源,如果这些都加载在内存中,不卸载那么很有可能会造成游戏崩溃。就像一个容器只往里添加而不往外拿,那么再大的容器也会被撑满。所以ab包什么时候卸载,卸载哪些包,就会是一个大问题。本文使用引用计数的方法解决ab包资源的管理问题。

首先需要明确需要管理哪些引用,就从UI面板的打开生命周期来看,一个UI会绑定一个预制体,加载预制体的ab包再实例化该游戏物体,那么这里会存在游戏物体与这个ab包之间的引用;其次在ab包加载的过程中,ab包又会与它依赖的包之间存在包与包的引用,引用关系如下:

对ab包来说,在更新自身引用计数的同时,也需要更新对依赖包的引用计数。最后当ab包的引用为0时,即可卸载这个ab包。对游戏物体来说,只需要保存对单个ab包的引用计数即可,不需要对包的依赖也进行计数。所以可以在代码中创建一个单独的类,用来保存ab包与游戏对象之间的引用计数。

一个ab包可以被多个游戏物体引用,一个游戏物体也可以引用多个游戏物体,是一种多对多的关系,游戏物体的生命周期才是ab包引用更新的关键。

  1. public class AssetReferenceBind : MonoBehaviour
  2. {
  3. //单个包引用绑定结构
  4. private class ReferenceBind
  5. {
  6. //已加载的ab包
  7. public LoadedAssetBundle bundle;
  8. //引用该包的游戏物体list
  9. public List<GameObject> referenceGos = new List<GameObject>();
  10. }
  11. //ab包名与包引用绑定关系字典
  12. private static Dictionary<string,ReferenceBind> distReferenceBind = new Dictionary<string, ReferenceBind> ();
  13. }

在资源加载完毕后,在UI基类代码中,调用绑定函数,这样不用每个UI类都需要写绑定方法,也不容易出错。

  1. //游戏物体与ab包之间引用绑定
  2. public static AssetBundle Check(GameObject go, string assetBundleName, LoadedAssetBundle loadedAssetBundle)
  3. {
  4. ReferenceBind reference;
  5. if(!distReferenceBind.TryGetValue(assetBundleName, out reference))
  6. {
  7. reference = new ReferenceBind();
  8. distReferenceBind[assetBundleName] = reference;
  9. }
  10. if(loadedAssetBundle != null)
  11. {
  12. //先移除旧的绑定资源
  13. if (reference.bundle != null)
  14. UIManager.Instance.unLoadAssetBundle(assetBundleName);
  15. reference.bundle = loadedAssetBundle;
  16. }
  17. if (reference.bundle == null)
  18. return null;
  19. if(!reference.referenceGos.Contains(go))
  20. reference.referenceGos.Add(go);
  21. return reference.bundle.assetBundle;
  22. }
  1. //在ui基类中调用绑定
  2. AssetReferenceBind.Check(ui.gameObject, UIManager.Instance.getUIAssetBundleName(uiname), assetBundle);

至此已完成游戏物体与ab包之间的引用绑定操作,加上前面文章ab包的加载中已完成ab包之间的引用计数,绑定相关的引用计数已OK。接下来就是卸载,首先卸载游戏物体与ab包之间的引用。

  1. public static void unLoadUnuseAssets()
  2. {
  3. foreach(var referenceBind in distReferenceBind)
  4. {
  5. for (var i = referenceBind.Value.referenceGos.Count - 1; i>=0; i--)
  6. {
  7. if (!referenceBind.Value.referenceGos[i])//游戏物体为null,从引用list中移除
  8. referenceBind.Value.referenceGos.RemoveAt(i);
  9. }
  10. //没有游戏对象引用时,清除包的引用
  11. if (referenceBind.Value.referenceGos.Count == 0 && referenceBind.Value.bundle != null)
  12. {
  13. UIManager.Instance.unLoadAssetBundle(referenceBind.Key);
  14. }
  15. }
  16. }

卸载包与包之间的依赖引用。

  1. /**
  2. 卸载ab包资源及其依赖包资源引用
  3. */
  4. public void unLoadAssetBundle(string assetBundleName)
  5. {
  6. unLoadSingleBundle(assetBundleName);
  7. string[] dependencies = null;
  8. string relativePath = assetBundleName;
  9. dependencies = mainBundleManifest.GetAllDependencies(relativePath);
  10. foreach (string dependency in dependencies)
  11. {
  12. unLoadSingleBundle(dependency);
  13. }
  14. }
  15. /**
  16. 卸载单个ab包资源引用计数
  17. */
  18. public void unLoadSingleBundle(string assetBundleName)
  19. {
  20. LoadedAssetBundle assetBundle = getLoadedAssetBundle(assetBundleName);
  21. if (assetBundle == null)
  22. return;
  23. if (assetBundle.referencedCount <= 0)
  24. Debug.LogWarning("unLoadSingleBundle {0} referencedCount has already zero");
  25. else
  26. assetBundle.referencedCount--;
  27. }

至此ab包的引用,随着游戏物体的销毁,引用计数更新。但此时还只是更新了引用,并未在内存中真实的卸载ab包资源。接下来就是真正卸载ab包资源的操作。

  1. /**
  2. 清除引用计数为0的ab包资源
  3. */
  4. public void unLoadUnuseAssets()
  5. {
  6. //先更新游戏物体与包之间的引用
  7. AssetReferenceBind.unLoadUnuseAssets();
  8. LoadedAssetBundle loadedAssetBundle;
  9. string key;
  10. for(var i= assetBundleNames.Count-1; i>=0; i--)
  11. {
  12. key = assetBundleNames[i];
  13. loadedAssetBundle = loadedAssetBundles[key];
  14. //再卸载计数为0的包资源
  15. if (loadedAssetBundle.referencedCount <= 0)
  16. {
  17. loadedAssetBundles.Remove(key);
  18. assetBundleNames.RemoveAt(i);
  19. loadedAssetBundle.unLoad();
  20. }
  21. }
  22. }

当然ab包的卸载也不需要实时操作,频繁的操作内存本身也是一直消耗,所以一般会预设一个内存峰值,当游戏内内存达到该值时,再去卸载一些无用的ab包,才是相对合理的操作。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/341558
推荐阅读
相关标签
  

闽ICP备14008679号