对象池基本介绍

类对象池
提前缓存一些基础类的对象,在其他管理类使用时直接从类对象池中取出。
类对象池需要自行实现还原的方法,因为每个具体的类不一样,所以每个类的变量修改后返回到对象池时需要自行重置
在下面的AssetBundle Manager中,AssetBundleItem
这个由对象池管理的类就自己实现了一个Reset方法
需要重置的原因是我们的对象池使用Stack<T>
,每一次Pop出来的对象都必须的是一样的
AssetBundle管理
读取配置表和依赖加载的管理
资源池管理
资源池管理(ResouceManager)是Asset Bundle管理的上层。
其中异步加载通过使用协程和循环来控制每一帧资源加载的容量来流畅加载。
资源池重点处理的是资源,图片、声音、视频、文字等,还包括未实例化的Prefab。
资源池为上层提供资源加载的接口。
对象池管理
对象池管理(ObjectManager)是资源池管理的上层。
针对需要实例化的对象进行缓存,根据对象是否常用来决定是否放进对象池中。其中异步加载需要实现取消加载,对象池中的对象可能在加载中途不需要加载了。
类对象池
新建ClassObjectPool
脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| using System.Collections.Generic;
public class ClassObjectPool<T> where T : class, new() { protected Stack<T> m_Pool = new Stack<T>(); protected int m_MaxCount = 0; protected int m_NoRecycleCount = 0;
public ClassObjectPool(int maxCount) { m_MaxCount=maxCount; for (int i = 0; i < maxCount; i++) { m_Pool.Push(new T()); } } public T Spawn(bool createIfEmpty) { if (m_Pool.Count > 0) { T rtn = m_Pool.Pop(); if (rtn == null) { if(createIfEmpty) { rtn = new T(); } } m_NoRecycleCount++; return rtn; } else { if (createIfEmpty) { T rtn = new T(); m_NoRecycleCount++; return rtn; } } return null; } public bool Recycle(T obj) { if(obj == null) { return false; } m_NoRecycleCount--; if(m_Pool.Count >= m_MaxCount && m_MaxCount>0) { obj = null; return false; } m_Pool.Push(obj); return true; } }
|
ObjectPoolManager
单例模板
1 2 3 4 5
| public class SingletonPattern<T> where T : new() { public static T Instance => _instance ??= new T(); private static T _instance; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| using System; using System.Collections.Generic;
public class ObjectPoolManager:SingletonPattern<ObjectPoolManager> { #region 类对象池的使用 protected Dictionary<Type, object> m_ClassPoolDic = new Dictionary<Type, object>();
public ClassObjectPool<T> GetOrCreatClassPool<T>(int maxCount) where T : class, new() { Type type = typeof(T); object outObj = null; if (!m_ClassPoolDic.TryGetValue(type, out outObj) || outObj == null) { ClassObjectPool<T> newPool = new ClassObjectPool<T>(maxCount); m_ClassPoolDic.Add(type, newPool); return newPool; } return outObj as ClassObjectPool<T>; } #endregion }
|
AssetBundleManager
- 读取Asset Bundle配置表
- 设置中间类进行引用计数
- 根据路径加载Asset Bundle
- 根据路径卸载Asset Bundle
- 为Resource Manager提供加载中间类,根据中间类释放资源,查找中间类等方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
| using System.Collections.Generic; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using UnityEngine;
public class AssetBundleManager : SingletonPattern<AssetBundleManager> { protected Dictionary<uint,ResourceItem> m_ResourceItemDic = new Dictionary<uint,ResourceItem>(); protected Dictionary<uint,AssetBundleItem> m_AssetBundleItemDic = new Dictionary<uint,AssetBundleItem>(); protected ClassObjectPool<AssetBundleItem> m_AssetBundleItemPool = ObjectPoolManager.Instance.GetOrCreatClassPool<AssetBundleItem>(500); public bool LoadAssetBundleConfig() { m_ResourceItemDic.Clear(); string configPath = Application.streamingAssetsPath + "/assetbundleconfig"; AssetBundle configAB = AssetBundle.LoadFromFile(configPath); TextAsset textAsset = configAB.LoadAsset<TextAsset>("AssetBundleConfig"); if (textAsset == null ) { Debug.LogError("AssetBundleConfig isn't exist"); return false; } using (MemoryStream ms = new MemoryStream(textAsset.bytes)) { BinaryFormatter bf = new BinaryFormatter(); AssetBundleConfig abConfig = (AssetBundleConfig)bf.Deserialize(ms);
for (int i = 0; i < abConfig.ABBasesList.Count; i++) { ABBase abBase = abConfig.ABBasesList[i]; ResourceItem resItem = new ResourceItem { m_Crc = abBase.Crc, m_AssetName = abBase.AssetName, m_AssetBundleName = abBase.ABName, m_DependAssetBundle = abBase.ABDependence, }; if(m_ResourceItemDic.ContainsKey(resItem.m_Crc)) { Debug.LogError("重复的Crc 资源名:" + resItem.m_AssetName + "AB包名:" + resItem.m_AssetBundleName); } else { m_ResourceItemDic.Add(resItem.m_Crc, resItem); } } return true; } } public ResourceItem LoadResourceAssetBundle(uint crc) { ResourceItem resItem = null; if(!m_ResourceItemDic.TryGetValue(crc, out resItem) || resItem == null) { Debug.LogErrorFormat("LoadResourceAssetBundle error: can not find crc {0} in AssetBundleConfig",crc.ToString()); return resItem; } resItem.m_AssetBundle = LoadAssetBundle(resItem.m_AssetBundleName); if(resItem.m_DependAssetBundle != null) { resItem.m_DependAssetBundle.ForEach(abName => { LoadAssetBundle(abName); }); } return resItem; } private AssetBundle LoadAssetBundle(string abName) { AssetBundleItem abItem = null; uint abCrc = CRC32.GetCRC32(abName); if(!m_AssetBundleItemDic.TryGetValue(abCrc, out abItem)) { AssetBundle assetBundle = null; string fullPath = Application.streamingAssetsPath + "/" + abName; #if UNITY_ANDROID assetBundle = AssetBundle.LoadFromFile(fullPath); #else if(File.Exists(fullPath)) { assetBundle = AssetBundle.LoadFromFile(fullPath); } #endif if (assetBundle == null) { Debug.LogError("Load AssetBundle Error:" + fullPath); } abItem = m_AssetBundleItemPool.Spawn(true); abItem.assetBundle = assetBundle; abItem.refCount++; m_AssetBundleItemDic.Add(abCrc, abItem); } else { abItem.refCount++; } return abItem.assetBundle; } public void ReleaseAsset(ResourceItem item) { if (item == null) return; if (item.m_DependAssetBundle != null && item.m_DependAssetBundle.Count > 0) { for (int i = 0; i < item.m_DependAssetBundle.Count; i++) { UnloadAssetBundle(item.m_DependAssetBundle[i]); } } UnloadAssetBundle(item.m_AssetBundleName); } private void UnloadAssetBundle(string abName) { uint abCrc = CRC32.GetCRC32(abName); AssetBundleItem abItem = null; if(m_AssetBundleItemDic.TryGetValue(abCrc,out abItem) && abItem != null) { abItem.refCount--; if(abItem.refCount <= 0 && abItem.assetBundle != null) { abItem.assetBundle.Unload(true); abItem.Reset(); m_AssetBundleItemPool.Recycle(abItem); m_AssetBundleItemDic.Remove(abCrc); } } } public ResourceItem FindResourceItem(uint crc) { ResourceItem item = null; m_ResourceItemDic.TryGetValue(crc, out item); return item; }
}
public class AssetBundleItem { public AssetBundle assetBundle = null; public int refCount;
public void Reset() { assetBundle=null; refCount = 0; } }
public class ResourceItem { public uint m_Crc = 0; public string m_AssetName = string.Empty; public string m_AssetBundleName = string.Empty; public List<string> m_DependAssetBundle = null; public AssetBundle m_AssetBundle = null; public Object m_Obj = null; public int m_GUID = 0; public float m_LastUseTime = 0.0f; protected int m_RefCount = 0; public int RefCount { get { return m_RefCount; } set { m_RefCount = value; if (m_RefCount < 0) { Debug.LogError("refcount < 0" + m_RefCount + " ," + (m_Obj != null ? m_Obj.name : "name is null")); } } } }
|