对象池
1、 概述
对象池系统提供了一个高效、易用的对象生命周期管理解决方案,支持普通C#对象和Unity GameObject两种类型的对象池化。系统采用静态门面模式,提供简洁的API接口,同时内部实现完善的池管理机制。
2、核心组件
IPoolable 接口
/// <summary>
/// 池对象接口,定义自动回收行为
/// </summary>
public interface IPoolable
{
void OnGet(); // 从池获取时调用
void OnRelease(); // 回收到池时调用
void OnDestroy(); // 销毁时调用
}
池化对象基类
PoolableObject<T> - C#对象池化基类
泛型设计,支持任意C#类
自动回收机制
继承自IPoolable接口
using UnityEngine.Pool;
/// <summary>
/// 泛型 C# 对象池抽象基类,支持自动回收机制。
/// </summary>
public abstract class PoolableObject<T> : IPoolable where T : PoolableObject<T>, new()
{
internal ObjectPool<T> pool; // 对象池引用
public void Release() // 回收当前实例到对象池
{
pool?.Release(this as T);
}
public virtual void OnGet() { } // 获取对象时的回调方法。
public virtual void OnRelease() { } // 回收对象时的回调方法。
public virtual void OnDestroy() { } // 销毁对象时的回调方法。
}
PoolableGameObject - GameObject池化基类
MonoBehaviour基类
支持Unity GameObject的完整生命周期
自动处理激活状态和父子关系
using UnityEngine;
using UnityEngine.Pool;
/// <summary>
/// MonoBehaviour 池对象抽象基类,支持自动回收机制。
/// </summary>
public abstract class PoolableGameObject : MonoBehaviour, IPoolable
{
internal ObjectPool<GameObject> pool; // 对象池引用。
public void Release() // 回收当前实例到对象池。
{
pool?.Release(gameObject);
}
public virtual void OnGet() { } // 获取对象时的回调方法。
public virtual void OnRelease() { } // 回收对象时的回调方法。
public virtual void OnDestroy() { } // 销毁对象时的回调方法
}
静态门面类 - Pool
提供统一的简化API:
Get<T>()
- 获取C#对象Get(prefab, parent)
- 获取GameObjectRelease(obj)
- 回收对象ClearAllPools()
- 清理所有池
using UnityEngine;
/// <summary>
/// 对象池静态门面类,提供统一的对象获取与回收接口
/// </summary>
public static class Pool
{
// 全局 C# 对象池最大容量
public static int ClassPoolMaxSize
{
get => PoolImpl.ClassPoolMaxSize;
set => PoolImpl.ClassPoolMaxSize = value;
}
// 全局 GameObject 对象池最大容量
public static int GameObjectPoolMaxSize
{
get => PoolImpl.GameObjectPoolMaxSize;
set => PoolImpl.GameObjectPoolMaxSize = value;
}
// 获取 C# 池对象实例
public static T Get<T>() where T : PoolableObject<T>, new()
{
return PoolImpl.Get<T>();
}
// 获取池化 GameObject 实例,可指定父节点
public static GameObject Get(GameObject prefab, Transform parent = null)
{
return PoolImpl.Get(prefab, parent);
}
// 回收 C# 池对象实例
public static void Release<T>(T obj) where T : PoolableObject<T>, new()
{
PoolImpl.Release(obj);
}
// 回收池化 GameObject 实例
public static void Release(GameObject go)
{
PoolImpl.Release(go);
}
// 清理所有对象池,释放所有资源
public static void ClearAllPools()
{
PoolImpl.ClearAllPools();
}
}
内部实现类 - PoolImpl
内部实现类,负责具体池管理逻辑
关键特性
懒初始化:对象池在首次使用时创建
分组管理:相同预制体的对象自动分组存放
自动绑定:自动为GameObject添加池化组件
容量控制:支持全局最大容量设置
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Pool;
/// <summary>
/// 对象池实现类,负责具体池管理逻辑。
/// </summary>
internal static class PoolImpl
{
private static readonly Dictionary<Type, object> classPools = new(); // C# 类型对象池集合。
private static readonly Dictionary<string, ObjectPool<GameObject>> prefabPools = new(); // GameObject 类型对象池集合。
private static Transform poolRoot; // 池化对象根节点。
private static readonly Dictionary<string, Transform> prefabRoots = new(); // 每种预制体的分组节点集合。
public static int ClassPoolMaxSize { get; set; } = 100; // C# 对象池最大容量。
public static int GameObjectPoolMaxSize { get; set; } = 100; // GameObject 对象池最大容量
// 获取或创建池化对象根节点
private static Transform PoolRoot
{
get
{
if (poolRoot == null)
{
var go = new GameObject("[PoolRoot]");
go.hideFlags = HideFlags.DontSave;
poolRoot = go.transform;
}
return poolRoot;
}
}
// 获取或创建指定预制体的分组节点
private static Transform GetPrefabRoot(string prefabName)
{
if (!prefabRoots.TryGetValue(prefabName, out var root))
{
var go = new GameObject(prefabName + "_Pool");
go.hideFlags = HideFlags.DontSave;
root = go.transform;
root.SetParent(PoolRoot, false);
prefabRoots[prefabName] = root;
}
return root;
}
// 获取 C# 池对象实例
public static T Get<T>() where T : PoolableObject<T>, new()
{
var type = typeof(T);
if (!classPools.TryGetValue(type, out var poolObj))
{
ObjectPool<T> pool = null;
pool = new ObjectPool<T>(
() => {
var obj = new T();
obj.pool = pool;
obj.OnGet();
return obj;
},
obj => obj.OnGet(),
obj => obj.OnRelease(),
obj => obj.OnDestroy(),
true,
ClassPoolMaxSize
);
classPools[type] = pool;
return pool.Get();
}
return ((ObjectPool<T>)poolObj).Get();
}
// 获取池化 GameObject 实例,可指定父节点
public static GameObject Get(GameObject prefab, Transform parent = null)
{
var key = prefab.name;
var groupRoot = GetPrefabRoot(key);
if (!prefabPools.TryGetValue(key, out var pool))
{
pool = new ObjectPool<GameObject>(
() => {
var go = GameObject.Instantiate(prefab, groupRoot);
var poolable = go.GetComponent<PoolableGameObject>();
if (poolable == null)
poolable = go.AddComponent<PoolableGameObject>();
poolable.pool = pool;
poolable.OnGet();
return go;
},
go => {
var poolable = go.GetComponent<PoolableGameObject>();
poolable?.OnGet();
go.SetActive(true);
go.transform.SetParent(parent ?? groupRoot, false);
},
go => {
var poolable = go.GetComponent<PoolableGameObject>();
poolable?.OnRelease();
go.SetActive(false);
go.transform.SetParent(groupRoot, false);
},
go => {
var poolable = go.GetComponent<PoolableGameObject>();
poolable?.OnDestroy();
GameObject.Destroy(go);
},
true,
GameObjectPoolMaxSize
);
prefabPools[key] = pool;
var obj = pool.Get();
obj.transform.SetParent(parent ?? groupRoot, false);
return obj;
}
var go2 = pool.Get();
go2.transform.SetParent(parent ?? groupRoot, false);
return go2;
}
// 回收 C# 池对象实例。
public static void Release<T>(T obj) where T : PoolableObject<T>, new()
{
obj.Release();
}
// 回收池化 GameObject 实例。
public static void Release(GameObject go)
{
var poolable = go.GetComponent<PoolableGameObject>();
poolable?.Release();
}
// 清理所有对象池并释放所有资源。
public static void ClearAllPools()
{
foreach (var pool in classPools.Values)
(pool as IDisposable)?.Dispose();
classPools.Clear();
foreach (var pool in prefabPools.Values)
pool.Clear();
prefabPools.Clear();
foreach (var root in prefabRoots.Values)
if (root != null) GameObject.Destroy(root.gameObject);
prefabRoots.Clear();
if (poolRoot != null)
{
GameObject.Destroy(poolRoot.gameObject);
poolRoot = null;
}
}
}
3、使用方法
池化C#对象
// 定义池化类
public class Bullet : PoolableObject<Bullet>
{
public float speed;
public override void OnGet()
{
// 对象被取出时的初始化
speed = 10f;
}
public override void OnRelease()
{
// 对象被回收时的清理
speed = 0f;
}
}
// 使用示例
var bullet = Pool.Get<Bullet>();
// 使用bullet...
bullet.Release(); // 手动回收
池化GameObject
// 定义池化组件
public class Enemy : PoolableGameObject
{
public int health = 100;
public override void OnGet()
{
health = 100;
gameObject.SetActive(true);
}
public override void OnRelease()
{
gameObject.SetActive(false);
}
}
// 使用示例
var enemyPrefab = Resources.Load<GameObject>("Enemy");
var enemy = Pool.Get(enemyPrefab, parentTransform);
// 使用enemy...
enemy.GetComponent<Enemy>().Release(); // 通过组件回收
4、特性说明
自动管理
自动分组:相同预制体的对象自动分组管理
层级管理:在场景中创建清晰的池化对象层级结构
容量控制:可设置全局最大容量限制
生命周期回调
提供完整的生命周期管理:
OnGet()
- 对象被取出时调用,用于初始化OnRelease()
- 对象被回收时调用,用于重置状态OnDestroy()
- 对象被销毁时调用,用于资源释放
内存管理
自动回收:支持对象自动回收到池中
资源清理:提供完整的池清理机制
防止泄漏:妥善处理场景切换时的资源释放
5、配置选项
全局容量设置
// 设置C#对象池最大容量
Pool.ClassPoolMaxSize = 200;
// 设置GameObject对象池最大容量
Pool.GameObjectPoolMaxSize = 50;
清理机制
// 清理所有对象池(通常在场景切换时调用)
Pool.ClearAllPools();
6、最佳实践
对象设计:池化对象应实现完整的状态重置逻辑
及时回收:使用完毕后及时调用Release()方法
避免外部引用:回收后不应继续持有对象引用
合理设置容量:根据实际使用情况调整池容量
7、注意事项
池化对象不应在构造函数中进行复杂初始化,应在OnGet()中完成
GameObject池化要求预制体必须包含PoolableGameObject组件
回收对象时,系统会自动处理激活状态和父子关系
在游戏退出或场景切换时建议调用ClearAllPools()进行清理
对象池系统通过简洁的API和完善的内部管理机制,为项目提供了高效的对象复用解决方案,能够显著提升游戏性能并减少内存分配。