在Unity中我们经常会用到对象池,使用对象池无非就是解决两个问题:
* 一是减少 new 时候寻址造成的消耗,该消耗的原因是内存碎片。
* 二是减少 Object.Instantiate 时内部进行序列化和反序列化而造成的CPU消耗。
想进一步了解对象池模式优化原理的同学可以参阅: [对象池模式:http://gpp.tkchu.me/object-pool.html](http://gpp.tkchu.me/object-pool.html),本篇主要讲如何实现一个精简并且灵活的对象池。
## 设计:
首先我们要弄清楚本篇对象池的几个概念,否则直接上代码大家会一头雾水。
从字面上理解对象池,池的意思就是容器。我们可以从池中获取一个对象(一条鱼),也可以向池中放入一个对象(一条鱼)。获取的操作我们叫Allocate(分配),而放入一个对象我们叫Recycle(回收)(ps:也有很多习惯叫Spawn 和 Despawn 的,这个看自己习惯了)。所以我们可以定义池的接口为如下:
```cs
public interface IPool<T>
{
T Allocate();
bool Recycle(T obj);
}
```
为什么要用泛型呢?因为笔者开头说过,本篇主要讲如何实现一个精简并且灵活的对象池。这个灵活很大一部分是通过泛型体现的。
前面有说过,池是容器的意思,在C#中可以是List,Queue或者Stack甚至是数组。所以对象池本身要维护一个容器。本篇我们选取Stack来作为池容器,原因是当我们在Allocate和Recycle时并不关心缓存的存储的顺序,只要求缓存对象的地址是连续的。代码如下所示:
```cs
using System.Collections.Generic;
public abstract class Pool<T> : IPool<T>
{
...
protected Stack<T> mCacheStack = new Stack<T>();
...
}
```
Pool是个抽象类,为什么呢? 因为笔者开头说过,本篇主要讲如何实现一个精简并且灵活的对象池。这个灵活很大一部分是通过抽象类体现的。
现在对象的存取和缓存接口都设计好了,那么这些对象是从哪里来的呢?我们分析下,创建对象我们知道有两种方式,反射构造方法和new一个对象。对象池的一个重要功能就是缓存,要想实现缓存就要求对象可以在对象池内部进行创建。所以我们要抽象出一个对象的工厂,代码如下所示:
```cs
public interface IObjectFactory<T>
{
T Create();
}
```
那么大家要问为什么要用工厂? 因为笔者开头说过,本篇主要讲如何实现一个精简并且灵活的对象池。这个灵活很大一部分是通过工厂体现的。
OK,现在对象的创建,存取,缓存的接口都设计好了。下面放出Pool的全部代码。
```cs
using System.Collections.Generic;
public abstract class Pool<T> : IPool<T>
{
#region ICountObserverable
/// <summary>
/// Gets the current count.
/// </summary>
/// <value>The current count.</value>
public int CurCount
{
get { return mCacheStack.Count; }
}
#endregion
protected IObjectFactory<T> mFactory;
protected Stack<T> mCacheStack = new Stack<T>();
/// <summary>
/// default is 5
/// </summary>
protected int mMaxCount = 5;
public virtual T Allocate()
{
return mCacheStack.Count == 0
? mFactory.Create()
: mCacheStack.Pop();
}
public abstract bool Recycle(T obj);
}
```
代码不多,设计阶段基本就这样。下面介绍如何实现一个简易的对象池。
## 对象池实现
首先要实现一个对象的创建器,代码如下所示:
```cs
using System;
public class CustomObjectFactory<T> : IObjectFactory<T>
{
public CustomObjectFactory(Func<T> factoryMethod)
{
mFactoryMethod = factoryMethod;
}
protected Func<T> mFactoryMethod;
public T Create()
{
return mFactoryMethod();
}
}
```
比较简单,只是维护了一个返回值为T的委托(如果说得有误请指正)。
对象池实现:
```cs
using System;
/// <summary>
/// unsafe but fast
/// </summary>
/// <typeparam name="T"></typeparam>
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);
mResetMethod = resetMethod;
for (int i = 0; i < initCount; i++)
{
mCacheStack.Push(mFactory.Create());
}
}
public override bool Recycle(T obj)
{
mResetMethod.InvokeGracefully(obj);
mCacheStack.Push(obj);
return true;
}
}
```
实现也很简单,这里不多说了。
## 如何使用?
```cs
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);
```
运行结果:
```cs
fishPool.CurCount:100
fishPool.CurCount:99
fishPool.CurCount:100
fishPool.CurCount:90
```
OK,本篇就介绍到这里
转载请注明地址:凉鞋的笔记:[liangxiegame.com](http://liangxiegame.com)
## 更多内容
* QFramework 地址:[https://github.com/liangxiegame/QFramework](https://github.com/liangxiegame/QFramework)
* QQ 交流群:[623597263](http://shang.qq.com/wpa/qunwpa?idkey=706b8eef0fff3fe4be9ce27c8702ad7d8cc1bceabe3b7c0430ec9559b3a9ce66)
* **Unity 进阶小班**:
* 主要训练内容:
* 框架搭建训练(第一年)
* 跟着案例学 Shader(第一年)
* 副业的孵化(第二年、第三年)
* 权益、授课形式等具体详情请查看[《小班产品手册》](https://liangxiegame.com/master/intro):https://liangxiegame.com/master/intro
* 关注公众号:liangxiegame 获取第一时间更新通知及更多的免费内容。
![](http://file.liangxiegame.com/38eccb55-40b2-4845-93d6-f5fb50ff9492.png)
- 正文
- Unity 游戏框架搭建 2017(一)概述
- Unity 游戏框架搭建 2017(二)单例的模板
- Unity 游戏框架搭建 2017(三)MonoBehaviour 单例的模板
- Unity 游戏框架搭建 2017(四)简易有限状态机
- Unity 游戏框架搭建 2017(五)简易消息机制
- Unity 游戏框架搭建 2017 (六) 关于框架的一些好文和一些思考
- Unity 游戏框架搭建 2017 (七) 减少加班利器-QApp类
- Unity 游戏框架搭建 2017 (八) 减少加班利器-QLog
- Unity 游戏框架搭建 2017 (九) 减少加班利器-QConsole
- Unity 游戏框架搭建 2017 (十) QFramework v0.0.2小结
- Unity 游戏框架搭建 2017 (十一) 简易 AssetBundle 打包工具 (一)
- Unity 游戏框架搭建 2017 (十二) 简易 AssetBundle 打包工具 (二)
- Unity 游戏框架搭建 2017 (十三) 无需继承的单例的模板
- Unity 游戏框架搭建 2017 (十四) 优雅的 QSingleton (零) QuickStart
- Unity 游戏框架搭建 2017 (十四) 优雅的 QSingleton (一) Singleton 单例实现
- Unity 游戏框架搭建 2017 (十四) 优雅的 QSingleton (二) MonoSingleton单例实现
- Unity 游戏框架搭建 2017 (十四) 优雅的 QSignleton (三) 通过属性器实现 Singleton
- Unity 游戏框架搭建 2017 (十四) 优雅的 QSingleton (四) 属性器实现 Mono 单例
- Unity 游戏框架搭建 2017 (十四) 优雅的 QSingleton (五) 优雅地进行GameObject命名
- Unity 游戏框架搭建 2017 (十五) 优雅的 QChain (零)
- Unity 游戏框架搭建 2017 (十六) v0.0.3 架构调整
- Unity 游戏框架搭建 2017 (十七) 静态扩展GameObject 实现链式编程
- Unity 游戏框架搭建 2017 (十八) 静态扩展 + 泛型实现 transform 的链式编程
- Unity 游戏框架搭建 2017 (十九) 简易对象池
- Unity 游戏框架搭建 2017 (二十) 安全的对象池
- Unity 游戏框架搭建 2017 (二十一) 使用对象池时的一些细节
- Unity 游戏框架搭建 2017 (二十二) 简易引用计数器
- Unity 游戏框架搭建 2017 (二十三) 重构小工具 Platform
- Unity 游戏框架搭建 2017 (二十四) 小结