在进行平时的功能开发时,对象池是一个比较常见的工具,用来减少GC的性能消耗,个人总结下来,对象池的关键有如下几点
- 管理使用中元素的集合,可以使是List
- 回收元素的集合,即池子本身,可以是Queue
- 得到元素的方法
- 回收元素的方法
- 回收所有元素的方法
- 按照需求,可以给池子来个最大数量
- 按照需求,可以来个初始化数量
- 对象池创建的是肉体,数据才是灵魂
- 对象池中的元素使用完之后,或者重复使用前,确保上面的旧数据已经清理完毕
1. 一个例子
csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class ObjectPool<T> where T : Component
{
[SerializeField]
protected T Obj;
/// <summary>
/// 初始化数量
/// </summary>
protected int initalSize = 10;
/// <summary>
/// 最大数量
/// </summary>
protected int maxSize = 50;
/// <summary>
/// 池本身
/// </summary>
protected Queue<T> recycleQueue = new Queue<T>();
/// <summary>
/// 正在使用的元素集合
/// </summary>
protected List<T> usingList = new List<T>();
/// <summary>
/// 池结点
/// </summary>
protected Transform poolContainer;
/// <summary>
/// 得到的回调
/// </summary>
public Action<T> GetCallback;
/// <summary>
/// 回收回调
/// </summary>
public Action<T> RecycleCallback;
protected void InitPool()
{
for (int i = 0; i < initalSize; i++)
{
CreateNewObj();
}
}
/// <summary>
/// 创建新对象
/// </summary>
/// <param name="active"></param>
/// <returns></returns>
protected virtual T CreateNewObj(bool active = false)
{
if (recycleQueue.Count == maxSize)
{
return null;
}
var obj = GameObject.Instantiate(Obj, poolContainer);
obj.gameObject.SetActive(active);
if (active)
{
usingList.Add(obj);
}
else
{
recycleQueue.Enqueue(obj);
}
return obj;
}
/// <summary>
/// 从池中得到对象
/// </summary>
/// <returns></returns>
public virtual T Get()
{
T obj = null;
if (recycleQueue.Count == 0)
{
obj = CreateNewObj();
usingList.Add(obj);
}
if (recycleQueue.Count > 0)
{
obj = recycleQueue.Dequeue();
obj.gameObject.SetActive(true);
usingList.Add(obj);
}
GetCallback?.Invoke(obj);
return obj;
}
public void Recycle(T obj)
{
if (recycleQueue.Count < maxSize)
{
recycleQueue.Enqueue(obj);
usingList.Remove(obj);
obj.gameObject.SetActive(false);
obj.transform.SetParent(poolContainer);
}
RecycleCallback?.Invoke(obj);
}
/// <summary>
/// 回收所有
/// </summary>
public void RecycleAll()
{
foreach (var obj in usingList.ToArray())
{
Recycle(obj);
}
}
}
2. 注意事项
即标红的这两点,个人认为是在使用对象池中最重要的地方,在上文中,使用了一个RecycleCallback回调,来模拟数据回收的回调,实际在使用时可能会调用元素自身的一个回收方法
比如

这样就确保了,元素在回收回对象池时,是"干净"的,那么下次再从池中取得元素就可以正常使用,否则会有残留数据影响。比如旧的元素上可能会注册一些事件,但是因为没有清除数据,所以再次使用时,因为元素本身只是回收进对象池,没有销毁,所以还是会触发旧的注册的事件