QFramework 是一套 渐进式 的 快速开发 框架。目标是作为无框架经验的公司、独立开发者、以及 Unity3D 初学者们的 第一套框架。框架内部积累了多个项目的在各个技术方向的解决方案。学习成本低,接入成本低,重构成本低,二次开发成本低,文档内容丰富(提供使用方式以及原理、开发文档)。github:https://github.com/liangxiegame/QFramework
在Unity中我们经常会用到对象池,使用对象池无非就是解决两个问题:
- 一是减少new时候寻址造成的消耗,该消耗的原因是内存碎片。
- 二是减少Object.Instantiate时内部进行序列化和反序列化而造成的CPU消耗。
https://blog.csdn.net/dengshunhao/article/details/80944994
首先来看对象池的老祖宗,定义了一个分配函数以及回收函数
public interface IPool<T>
{
T Allocate();
bool Recycle(T obj);
}
定义一个计算当前剩余可分配数量的接口ICountObserveAble,这个值其实就是后面栈元素的数量
//当前栈的数量,pool继承于它
public interface ICountObserveAble
{
int CurCount { get; }
}
定义一个Pool,继承上面两个接口,并实现里面的方法
using System.Collections.Generic;
public abstract class Pool<T> : IPool<T>,ICountObserveAble
{
#region ICountObserverable
//返回池的数量
public int CurCount
{
get { return mCacheStack.Count; }
}
#endregion
//抽象工厂
protected IObjectFactory<T> mFactory;
protected readonly Stack<T> mCacheStack = new Stack<T>(); //池容器
//默认为12
protected int mMaxCount = 12;
//分配
public virtual T Allocate()
{
return mCacheStack.Count == 0
? mFactory.Create()
: mCacheStack.Pop(); //当栈还有元素时就pop,没有就重新创建
}
//回收
public abstract bool Recycle(T obj);
}
还有定义一个创建方法:
//抽象工厂
public interface IObjectFactory<T>
{
T Create();
}
①适合用于项目开发SimpleObjectPool :
框架定义了一个对action的扩展方法
public static bool InvokeGracefully<T>(this Action<T> selfAction, T t)
{
if (null != selfAction)
{
selfAction(t);
return true;
}
return false;
}
完整实现:
public class SimpleObjectPool<T> : Pool<T>
{
readonly Action<T> mResetMethod; //回收方法,由初始化时决定
public SimpleObjectPool(Func<T> factoryMethod, Action<T> resetMethod = null,int initCount = 0)
{
mFactory = new CustomObjectFactory<T>(factoryMethod); //factoryMethod是传入对象的初始化方法
mResetMethod = resetMethod; //回收方法
//初始化
for (int i = 0; i < initCount; i++)
{
mCacheStack.Push(mFactory.Create()); //mFactory.Create()调用的就是factoryMethod方法
}
}
public override bool Recycle(T obj)
{
mResetMethod.InvokeGracefully(obj); //调用该对象的回收方法
mCacheStack.Push(obj); //压入栈
return true;
}
}
示例程序:
public class SimpleObjectPoolExample : MonoBehaviour
{
/// <summary>
///
/// </summary>
public class Fish
{
}
private void Start()
{
var fishPool = new SimpleObjectPool<Fish>(() => new Fish(), null, 100);
Log.I("fishPool.CurCount:{0}", fishPool.CurCount);
var fishOne = fishPool.Allocate();
Log.I("fishPool.CurCount:{0}", fishPool.CurCount);
fishPool.Recycle(fishOne);
Log.I("fishPool.CurCount:{0}", fishPool.CurCount);
for (int i = 0; i < 10; i++)
{
fishPool.Allocate();
}
Log.I("fishPool.CurCount:{0}", fishPool.CurCount);
}
}
②适合用于库级开发,更多限制,要求开发者一开始就想好,更安全的SafeObjectPool :
定义以下两个接口,需要使用安全对象池的需要继承这两个接口:
//将回收操作开放给用户,因为用户可能需要在回收对象之前进行一些操作,并且实现的时候需要调用该对象池对象回收对象
public interface IPoolType
{
void Recycle2Cache();
}
//给泛型加上约束 保证T是继承IPoolable的,同时将回收操作开放
public interface IPoolable
{
void OnRecycled(); //对象的回收操作
bool IsRecycled { get; set; } //表示对象是否被回收过
}
SafeObjectPool的完整实现(可以无限取,但是缓存池中就存最大值数量的元素):
//对象池
public class SafeObjectPool<T> : Pool<T>, ISingleton where T : IPoolable, new()
{
#region Singleton
void ISingleton.OnSingletonInit() {}
protected SafeObjectPool()
{
mFactory = new DefaultObjectFactory<T>();
}
public static SafeObjectPool<T> Instance
{
get { return SingletonProperty<SafeObjectPool<T>>.Instance; }
}
//释放,即置空
public void Dispose()
{
SingletonProperty<SafeObjectPool<T>>.Dispose();
}
#endregion
//初始化 maxCount:最大数量 initCount:初始化数量
public void Init(int maxCount, int initCount)
{
MaxCacheCount = maxCount;
if (maxCount > 0)
{
initCount = Math.Min(maxCount, initCount);
}
//当前对象池内的对象数量小于要初始化的数量,开始初始化
if (CurCount < initCount)
{
for (int i = CurCount; i < initCount; ++i)
{
//初始化化之后的,并让其处于回收状态
Recycle(new T());
}
}
}
public int MaxCacheCount
{
get { return mMaxCount; }
set
{
mMaxCount = value;
if (mCacheStack != null)
{
if (mMaxCount > 0)
{
if (mMaxCount < mCacheStack.Count)
{
int removeCount = mMaxCount - mCacheStack.Count;
while (removeCount > 0)
{
mCacheStack.Pop();
--removeCount;
}
}
}
}
}
}
//分配一个对象
public override T Allocate()
{
var result = base.Allocate(); //如果栈的数量>0,则栈顶元素pop
result.IsRecycled = false; //分配的时候置位false
return result;
}
//回收一个对象
public override bool Recycle(T t)
{
if (t == null || t.IsRecycled) //判断是否已经回收
{
return false;
}
//当超过设置的最大限制时不push入栈中,只是执行回收函数,之后会自动销毁
if (mMaxCount > 0)
{
if (mCacheStack.Count >= mMaxCount)
{
t.OnRecycled();
return false;
}
}
t.IsRecycled = true;
t.OnRecycled(); //对象的回收操作
mCacheStack.Push(t);
return true;
}
}
只看这些还是有点懵的,看下作者提供的示例就很清晰了
public class SafeObjectPoolExample : MonoBehaviour
{
class Msg : IPoolable,IPoolType
{
#region IPoolAble 实现
public void OnRecycled()
{
Log.I("OnRecycled");
}
public bool IsRecycled { get; set; }
#endregion
#region IPoolType 实现
public static Msg Allocate()
{
return SafeObjectPool<Msg>.Instance.Allocate();
}
public void Recycle2Cache()
{
SafeObjectPool<Msg>.Instance.Recycle(this);
}
#endregion
}
private void Start()
{
SafeObjectPool<Msg>.Instance.Init(100, 50);
Log.I("msgPool.CurCount:{0}", SafeObjectPool<Msg>.Instance.CurCount);
var fishOne = Msg.Allocate();
Log.I("msgPool.CurCount:{0}", SafeObjectPool<Msg>.Instance.CurCount);
fishOne.Recycle2Cache();
Log.I("msgPool.CurCount:{0}", SafeObjectPool<Msg>.Instance.CurCount);
for (int i = 0; i < 10; i++)
{
Msg.Allocate();
}
Log.I("msgPool.CurCount:{0}", SafeObjectPool<Msg>.Instance.CurCount);
}
}
想进一步了解对象池模式优化原理的同学可以参阅: 对象池模式:http://gpp.tkchu.me/object-pool.html
参考:
1. 对象池模式:http://gpp.tkchu.me/object-pool.html