为什么用对象池?
作用:因为Mono内存在Unity中不能手动释放,当其内存超过上限时,会先触发GC释放没有用到的内存空间,如果还不够则会扩充。其容量一旦被撑大,项目所占的内存就会跟着增大。使用对象池可以减少对象创建,缓解内存压力。
对象池示意 这里通过一个栈存储对象
m_MaxCount 表示最大储存个数
m_NoRecycleNum 用来记录未归还的对象
public class ClassObjectPool<T> where T : class,new(){
protected Stack<T> m_Pool = new Stack<T>();
protected int m_MaxCount = 0; //最大储存个数
protected int m_NoRecycleNum = 0;//未归还的对象
//构造函数时限制最大储存个数 并压入对象
public ClassObjectPool(int max_count){
m_MaxCount = max_count;
for(int i = 0;i<max_count;i++){
m_Pool.Push(new T());
}
}
/// <summary>
/// 从池中取对象
/// </summary>
/// <param name="create_if_pool_empty">如果池是空的则创建</param>
/// <returns></returns>
public T Spawn(bool create_if_pool_empty = true){
if(m_Pool.Count > 0){
T res = m_Pool.Pop();
if(res == null){
if(create_if_pool_empty){
res = new T();
m_NoRecycleNum++;
}
}
if(res != null)
m_NoRecycleNum++;
return res;
}
else{
if(create_if_pool_empty){
m_NoRecycleNum++;
return new T();
}
}
return null;
}
/// <summary>
/// 把对象放回池中
/// </summary>
/// <param name="obj">还回对象</param>
/// <returns></returns>
public bool Recycle(T obj){
if(obj == null)
return false;
m_NoRecycleNum--;
//如果池内对象已经达到最大值,则不放入池中
if(m_MaxCount > 0 && m_Pool.Count >= m_MaxCount){
obj = null;
return false;
}
MethodInfo[] methods = obj.GetType().GetMethods();
foreach(MethodInfo info in methods){
//如果对象拥有Reset()方法 则调用一下
if(info.Name == "Reset"){
obj.GetType().InvokeMember("Reset",BindingFlags.InvokeMethod|BindingFlags.Default,null,obj,new object[]{});
}
}
m_Pool.Push(obj);
return true;
}
}
将对象归还到对象池,如果对象的信息需要重置,则需要重置再归还。可以在对象中添加重置方法,我这里在归还的时候使用反射调用
public class AssetBundleItem{
public AssetBundle assetBundle = null;
public int refCount = 0;
public void Reset(){
assetBundle = null;
refCount = 0;
}
以上是对象池的基础代码,但是这样还是可以 new 出多个相同类型的 ClassObjectPool,所以我采用一个字典,将已创建的对象池缓存起来统一管理
//缓存ObjectManager创建的对象池
protected Dictionary<Type, object> obj_dic = new Dictionary<Type, object>();
//获得或者创建一个对象池
//当有对象池的时候则直接取,没有的时候按count的数量创建
public ClassObjectPool<T> GetOrCreteObject<T>(int count = 1) where T : class, new()
{
Type type = typeof(T);
object out_obj = null;
if (!obj_dic.TryGetValue(type, out out_obj))
{
ClassObjectPool<T> new_pool = new ClassObjectPool<T>(count);
obj_dic.Add(type, new_pool);
out_obj = new_pool;
}
return out_obj as ClassObjectPool<T>;
}