GFramework/docs/core/pool.md
GeWuYou 1dc173e4df docs(core): 添加核心模块架构文档
- 添加 Architecture 包使用说明文档,介绍 MVC 架构模式实现
- 添加 Command 包使用说明文档,阐述命令模式设计和实现
- 添加 Controller 包使用说明文档,描述控制器接口规范
- 添加 Environment 包使用说明文档,定义环境配置功能
- 添加 Events 包使用说明文档,提供事件系统完整介绍
2026-02-11 12:52:14 +08:00

952 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 对象池系统 (Object Pool System)
## 概述
GFramework 的对象池系统是一个高效的内存管理机制旨在减少垃圾回收GC压力通过复用对象实例来提高应用程序性能。该系统实现了对象的创建、获取、释放和销毁的完整生命周期管理。
**核心优势:**
- **减少 GC 压力**:复用对象实例,避免频繁的内存分配和回收
- **提高性能**:避免重复创建开销大的对象
- **灵活管理**:支持多个独立的对象池,按需分类管理
- **自动生命周期**:与 System 生命周期集成,自动管理对象销毁
- **类型安全**:基于泛型实现,编译时类型检查
## 核心组件
### IPoolableObject 接口
定义了可池化对象的行为规范,所有需要池化的对象都必须实现此接口。
```csharp
public interface IPoolableObject
{
/// <summary>
/// 当对象从池中获取时调用,用于初始化或重置对象状态
/// </summary>
void OnAcquire();
/// <summary>
/// 当对象被放回池中时调用,用于清理对象状态
/// </summary>
void OnRelease();
/// <summary>
/// 当对象池被销毁时调用,用于执行最终清理
/// </summary>
void OnPoolDestroy();
}
```
**生命周期:**
```
创建 → Acquire从池取出→ 使用 → Release放回池→ 可再次 Acquire
Pool Destroy → OnPoolDestroy → 销毁
```
### IObjectPoolSystem 接口
定义了对象池系统的基本操作接口。
```csharp
public interface IObjectPoolSystem<TKey, TObject>
where TObject : IPoolableObject
where TKey : notnull
{
/// <summary>
/// 从指定键的对象池中获取一个对象
/// </summary>
/// <param name="key">对象池的键值</param>
/// <returns>获取到的对象实例</returns>
TObject Acquire(TKey key);
/// <summary>
/// 将对象释放回指定键的对象池中
/// </summary>
/// <param name="key">对象池的键值</param>
/// <param name="obj">需要释放的对象</param>
void Release(TKey key, TObject obj);
/// <summary>
/// 清空所有对象池,销毁所有池中的对象
/// </summary>
void Clear();
}
```
### AbstractObjectPoolSystem 抽象类
实现了 `IObjectPoolSystem` 接口的具体逻辑,提供了对象池管理的完整实现。
**核心特性:**
- 使用字典存储多个对象池,以键区分不同的对象池
- 使用栈Stack存储池中的对象实现 LIFO后进先出管理
- 提供获取和释放对象的方法
- 通过抽象方法 `Create` 让子类决定如何创建对象
- 在系统销毁时自动清理所有对象池
**内部实现:**
```csharp
public abstract class AbstractObjectPoolSystem<TKey, TObject>
: AbstractSystem, IObjectPoolSystem<TKey, TObject>
where TObject : IPoolableObject
where TKey : notnull
{
// 存储对象池的字典,键为池标识,值为对应类型的对象栈
protected readonly Dictionary<TKey, Stack<TObject>> Pools = new();
// 获取对象
public TObject Acquire(TKey key)
{
if (!Pools.TryGetValue(key, out var pool))
{
pool = new Stack<TObject>();
Pools[key] = pool;
}
var obj = pool.Count > 0
? pool.Pop() // 从池中取出
: Create(key); // 创建新对象
obj.OnAcquire(); // 调用对象的获取钩子
return obj;
}
// 释放对象
public void Release(TKey key, TObject obj)
{
obj.OnRelease(); // 调用对象的释放钩子
if (!Pools.TryGetValue(key, out var pool))
{
pool = new Stack<TObject>();
Pools[key] = pool;
}
pool.Push(obj); // 放回池中
}
// 清空所有对象池
public void Clear()
{
foreach (var obj in Pools.Values.SelectMany(pool => pool))
{
obj.OnPoolDestroy(); // 调用对象的销毁钩子
}
Pools.Clear();
}
// 子类实现:创建新对象
protected abstract TObject Create(TKey key);
// 系统销毁时自动清空对象池
protected override void OnDestroy()
{
Clear();
}
}
```
## 基本使用
### 1. 定义池化对象
首先,创建一个实现 `IPoolableObject` 接口的类。
```csharp
public class Bullet : IPoolableObject
{
public int Damage { get; private set; }
public float Speed { get; private set; }
public Vector3 Position { get; private set; }
public Vector3 Direction { get; private set; }
public bool IsActive { get; private set; }
public void OnAcquire()
{
// 从池中获取时调用,初始化对象状态
IsActive = true;
}
public void OnRelease()
{
// 放回池中时调用,清理对象状态
IsActive = false;
Damage = 0;
Speed = 0;
Position = Vector3.Zero;
Direction = Vector3.Zero;
}
public void OnPoolDestroy()
{
// 对象池销毁时调用,执行最终清理
// 可以在这里释放非托管资源
}
// 设置子弹属性的方法
public void Setup(int damage, float speed, Vector3 position, Vector3 direction)
{
Damage = damage;
Speed = speed;
Position = position;
Direction = direction;
}
// 更新子弹逻辑
public void Update(float deltaTime)
{
Position += Direction * Speed * deltaTime;
}
}
```
### 2. 实现对象池系统
继承 `AbstractObjectPoolSystem<TKey, TObject>` 并实现 `Create` 方法。
```csharp
public class BulletPoolSystem : AbstractObjectPoolSystem<string, Bullet>
{
protected override Bullet Create(string key)
{
// 根据键值创建不同类型的子弹
return key switch
{
"standard" => new Bullet(),
"heavy" => new Bullet(),
"explosive" => new Bullet(),
_ => new Bullet()
};
}
protected override void OnInit()
{
// 可以预先创建一些对象放入池中
for (int i = 0; i < 10; i++)
{
var bullet = Create("standard");
bullet.OnAcquire();
bullet.OnRelease();
Release("standard", bullet);
}
}
}
```
### 3. 在架构中注册对象池系统
```csharp
public class GameArchitecture : Architecture
{
protected override void Init()
{
// 注册其他组件
RegisterModel(new PlayerModel());
RegisterSystem(new CombatSystem());
// 注册对象池系统
RegisterSystem(new BulletPoolSystem());
}
}
```
### 4. 使用对象池
```csharp
public class ShootingSystem : AbstractSystem
{
private BulletPoolSystem _bulletPool;
private List<Bullet> _activeBullets = new();
protected override void OnInit()
{
_bulletPool = this.GetSystem<BulletPoolSystem>();
this.RegisterEvent<ShootEvent>(OnShoot);
this.RegisterEvent<GameUpdateEvent>(OnUpdate);
}
private void OnShoot(ShootEvent e)
{
// 从对象池获取子弹
var bullet = _bulletPool.Acquire("standard");
// 设置子弹属性
bullet.Setup(
damage: e.Damage,
speed: 10.0f,
position: e.StartPosition,
direction: e.Direction
);
// 添加到活跃列表
_activeBullets.Add(bullet);
}
private void OnUpdate(GameUpdateEvent e)
{
// 更新所有活跃子弹
for (int i = _activeBullets.Count - 1; i >= 0; i--)
{
var bullet = _activeBullets[i];
bullet.Update(e.DeltaTime);
// 检查子弹是否需要销毁(例如:超出范围或击中目标)
if (ShouldDestroyBullet(bullet))
{
// 放回对象池
_bulletPool.Release("standard", bullet);
_activeBullets.RemoveAt(i);
}
}
}
private bool ShouldDestroyBullet(Bullet bullet)
{
// 简单示例:子弹超出一定范围则销毁
return bullet.Position.Length() > 1000.0f;
}
}
```
## 高级用法
### 1. 多键对象池管理
```csharp
public class ParticlePoolSystem : AbstractObjectPoolSystem<string, Particle>
{
protected override Particle Create(string key)
{
// 根据键值创建不同类型的粒子效果
return key switch
{
"explosion" => new Particle(explosionPrefab),
"smoke" => new Particle(smokePrefab),
"spark" => new Particle(sparkPrefab),
_ => throw new ArgumentException($"Unknown particle type: {key}")
};
}
// 提供便捷方法
public Particle SpawnExplosion(Vector3 position)
{
var particle = Acquire("explosion");
particle.Position = position;
particle.Play();
return particle;
}
}
// 使用
public class EffectSystem : AbstractSystem
{
private ParticlePoolSystem _particlePool;
protected override void OnInit()
{
_particlePool = this.GetSystem<ParticlePoolSystem>();
}
public void PlayExplosion(Vector3 position)
{
_particlePool.SpawnExplosion(position);
}
}
```
### 2. 动态对象池管理
```csharp
public class EnemyPoolSystem : AbstractObjectPoolSystem<string, Enemy>
{
protected override Enemy Create(string key)
{
// 根据敌人类型创建不同的敌人
var enemyPrefab = LoadEnemyPrefab(key);
return new Enemy(enemyPrefab);
}
// 动态注册新的敌人类型池
public void RegisterEnemyType(string enemyType)
{
if (!Pools.ContainsKey(enemyType))
{
Pools[enemyType] = new Stack<Enemy>();
// 预热:预先创建几个敌人放入池中
for (int i = 0; i < 3; i++)
{
var enemy = Create(enemyType);
enemy.OnAcquire();
enemy.OnRelease();
Release(enemyType, enemy);
}
}
}
}
// 使用
public class EnemySpawnerSystem : AbstractSystem
{
private EnemyPoolSystem _enemyPool;
protected override void OnInit()
{
_enemyPool = this.GetSystem<EnemyPoolSystem>();
// 注册不同类型的敌人
_enemyPool.RegisterEnemyType("goblin");
_enemyPool.RegisterEnemyType("orc");
_enemyPool.RegisterEnemyType("dragon");
}
public void SpawnEnemy(string enemyType, Vector3 position)
{
var enemy = _enemyPool.Acquire(enemyType);
enemy.Position = position;
enemy.Activate();
}
}
```
### 3. 对象池大小限制
```csharp
public class LimitedBulletPoolSystem : AbstractObjectPoolSystem<string, Bullet>
{
private const int MaxPoolSize = 50;
protected override Bullet Create(string key)
{
return new Bullet();
}
public new void Release(string key, Bullet obj)
{
// 检查对象池大小
if (Pools.TryGetValue(key, out var pool) && pool.Count >= MaxPoolSize)
{
// 池已满,不回收对象,让它被 GC 回收
return;
}
// 调用基类的 Release 方法
base.Release(key, obj);
}
}
```
### 4. 对象池统计和调试
```csharp
public class DebuggablePoolSystem : AbstractObjectPoolSystem<string, PoolableObject>
{
public Dictionary<string, int> PoolSizes => Pools.ToDictionary(
kvp => kvp.Key,
kvp => kvp.Value.Count
);
public int TotalPooledObjects => Pools.Values.Sum(stack => stack.Count);
public void LogPoolStatus()
{
foreach (var (key, stack) in Pools)
{
Console.WriteLine($"Pool [{key}]: {stack.Count} objects");
}
Console.WriteLine($"Total pooled objects: {TotalPooledObjects}");
}
protected override void OnDestroy()
{
LogPoolStatus();
base.OnDestroy();
}
}
```
## 使用场景
### 1. 游戏对象池
**适用对象:**
- 子弹、箭矢、投射物
- 敌人、NPC
- 爆炸效果、粒子系统
- UI 元素(提示、对话框)
**示例:子弹池**
```csharp
// 定义子弹
public class Bullet : IPoolableObject
{
public Vector3 Position { get; private set; }
public Vector3 Velocity { get; private set; }
public float Lifetime { get; private set; }
public void OnAcquire()
{
Lifetime = 5.0f; // 5秒后自动销毁
}
public void OnRelease()
{
Position = Vector3.Zero;
Velocity = Vector3.Zero;
}
public void OnPoolDestroy() { }
public void Update(float deltaTime)
{
Position += Velocity * deltaTime;
Lifetime -= deltaTime;
}
}
// 子弹对象池
public class BulletPoolSystem : AbstractObjectPoolSystem<string, Bullet>
{
protected override Bullet Create(string key) => new Bullet();
}
// 射击系统
public class ShootingSystem : AbstractSystem
{
private BulletPoolSystem _bulletPool;
private List<Bullet> _activeBullets = new();
protected override void OnInit()
{
_bulletPool = this.GetSystem<BulletPoolSystem>();
this.RegisterEvent<ShootEvent>(OnShoot);
this.RegisterEvent<GameUpdateEvent>(OnUpdate);
}
private void OnShoot(ShootEvent e)
{
var bullet = _bulletPool.Acquire("normal");
bullet.Position = e.StartPosition;
bullet.Velocity = e.Direction * e.Speed;
_activeBullets.Add(bullet);
}
private void OnUpdate(GameUpdateEvent e)
{
for (int i = _activeBullets.Count - 1; i >= 0; i--)
{
var bullet = _activeBullets[i];
bullet.Update(e.DeltaTime);
if (bullet.Lifetime <= 0)
{
_bulletPool.Release("normal", bullet);
_activeBullets.RemoveAt(i);
}
}
}
}
```
### 2. UI 元素池
**适用对象:**
- 对话框
- 提示框
- 菜单项
- 列表项
**示例:提示框池**
```csharp
public class Tooltip : IPoolableObject
{
public string Text { get; set; }
public bool IsActive { get; private set; }
public void OnAcquire()
{
IsActive = true;
}
public void OnRelease()
{
IsActive = false;
Text = "";
}
public void OnPoolDestroy() { }
public void Show(string text, Vector3 position)
{
Text = text;
// 更新 UI 位置和内容
}
}
public class TooltipPoolSystem : AbstractObjectPoolSystem<string, Tooltip>
{
protected override Tooltip Create(string key) => new Tooltip();
}
public class UISystem : AbstractSystem
{
private TooltipPoolSystem _tooltipPool;
protected override void OnInit()
{
_tooltipPool = this.GetSystem<TooltipPoolSystem>();
}
public void ShowTooltip(string text, Vector3 position)
{
var tooltip = _tooltipPool.Acquire("default");
tooltip.Show(text, position);
}
}
```
### 3. 网络消息对象池
**适用对象:**
- 网络包
- 协议消息
- 数据包
**示例:网络包池**
```csharp
public class NetworkPacket : IPoolableObject
{
public byte[] Data { get; private set; }
public int Length { get; private set; }
public void OnAcquire()
{
Data = Array.Empty<byte>();
Length = 0;
}
public void OnRelease()
{
// 清理敏感数据
if (Data != null)
{
Array.Clear(Data, 0, Data.Length);
}
Length = 0;
}
public void OnPoolDestroy() { }
public void SetData(byte[] data)
{
Data = data;
Length = data.Length;
}
}
public class PacketPoolSystem : AbstractObjectPoolSystem<string, NetworkPacket>
{
protected override NetworkPacket Create(string key) => new NetworkPacket();
}
```
## 最佳实践
### 1. 对象生命周期管理
```csharp
// ✅ 好的做法:确保所有对象都放回池中
public class BulletSystem : AbstractSystem
{
private List<Bullet> _activeBullets = new();
protected override void OnDestroy()
{
// 系统销毁时,确保所有活跃子弹都放回池中
foreach (var bullet in _activeBullets)
{
_bulletPool.Release("standard", bullet);
}
_activeBullets.Clear();
base.OnDestroy();
}
}
// ❌ 不好的做法:忘记放回对象,导致泄漏
public class BadBulletSystem : AbstractSystem
{
private List<Bullet> _activeBullets = new();
private void OnUpdate(GameUpdateEvent e)
{
// 子弹销毁时忘记放回池中
if (bullet.Lifetime <= 0)
{
_activeBullets.RemoveAt(i);
// 忘记调用 _bulletPool.Release(...)
}
}
}
```
### 2. 对象状态重置
```csharp
// ✅ 好的做法:在 OnRelease 中彻底重置对象状态
public class Bullet : IPoolableObject
{
public int Damage { get; set; }
public float Speed { get; set; }
public List<string> Tags { get; set; }
public Dictionary<string, object> Data { get; set; }
public void OnRelease()
{
// 重置所有属性
Damage = 0;
Speed = 0;
Tags?.Clear();
Data?.Clear();
// 也可以设置为新实例(如果性能允许)
Tags = new List<string>();
Data = new Dictionary<string, object>();
}
}
// ❌ 不好的做法:不完全重置状态
public class BadBullet : IPoolableObject
{
public List<string> Tags = new List<string>();
public void OnRelease()
{
// 只清空列表,但列表实例本身保留
// 这可能导致问题:如果其他代码持有列表引用
Tags.Clear();
}
}
```
### 3. 对象池预热
```csharp
// ✅ 好的做法:预先创建一些对象放入池中
public class BulletPoolSystem : AbstractObjectPoolSystem<string, Bullet>
{
protected override Bullet Create(string key) => new Bullet();
protected override void OnInit()
{
// 为常用的子弹类型预热对象池
var commonTypes = new[] { "standard", "heavy", "sniper" };
foreach (var type in commonTypes)
{
// 预先创建 5 个对象
for (int i = 0; i < 5; i++)
{
var bullet = Create(type);
bullet.OnAcquire();
bullet.OnRelease();
Release(type, bullet);
}
}
}
}
```
### 4. 对象池大小管理
```csharp
// ✅ 好的做法:限制对象池大小,避免内存浪费
public class BoundedPoolSystem : AbstractObjectPoolSystem<string, PooledObject>
{
private const int MaxPoolSize = 100;
public new void Release(string key, PooledObject obj)
{
if (Pools.TryGetValue(key, out var pool) && pool.Count >= MaxPoolSize)
{
// 池已满,不回收对象
return;
}
base.Release(key, obj);
}
}
// ✅ 好的做法:动态调整对象池大小
public class AdaptivePoolSystem : AbstractObjectPoolSystem<string, PooledObject>
{
private Dictionary<string, int> _peakUsage = new();
public new void Release(string key, PooledObject obj)
{
// 记录峰值使用量
if (Pools.TryGetValue(key, out var pool))
{
_peakUsage[key] = Math.Max(_peakUsage.GetValueOrDefault(key, 0), pool.Count);
}
// 根据使用情况动态调整
int maxAllowed = _peakUsage.GetValueOrDefault(key, 10) * 2;
if (pool.Count >= maxAllowed)
{
return; // 不回收
}
base.Release(key, obj);
}
}
```
### 5. 调试和监控
```csharp
// ✅ 好的做法:添加对象池统计功能
public class MonitoredPoolSystem : AbstractObjectPoolSystem<string, PooledObject>
{
private Dictionary<string, int> _acquireCount = new();
private Dictionary<string, int> _releaseCount = new();
public new PooledObject Acquire(string key)
{
_acquireCount[key] = _acquireCount.GetValueOrDefault(key, 0) + 1;
return base.Acquire(key);
}
public new void Release(string key, PooledObject obj)
{
_releaseCount[key] = _releaseCount.GetValueOrDefault(key, 0) + 1;
base.Release(key, obj);
}
public void PrintStatistics()
{
foreach (var key in Pools.Keys)
{
int acquired = _acquireCount.GetValueOrDefault(key, 0);
int released = _releaseCount.GetValueOrDefault(key, 0);
int leaked = acquired - released;
Console.WriteLine($"Pool [{key}]:");
Console.WriteLine($" Acquired: {acquired}");
Console.WriteLine($" Released: {released}");
Console.WriteLine($" Leaked: {leaked}");
Console.WriteLine($" Pool size: {Pools[key].Count}");
}
}
}
```
## 性能优化
### 1. 减少对象创建
```csharp
// ✅ 好的做法:对象池预热,避免运行时创建
public class PreheatedPoolSystem : AbstractObjectPoolSystem<string, Bullet>
{
protected override Bullet Create(string key) => new Bullet();
protected override void OnInit()
{
// 预热常用对象池
PreheatPool("standard", 20);
PreheatPool("heavy", 10);
}
private void PreheatPool(string key, int count)
{
for (int i = 0; i < count; i++)
{
var bullet = Create(key);
bullet.OnAcquire();
bullet.OnRelease();
Release(key, bullet);
}
}
}
```
### 2. 使用值类型作为键
```csharp
// ✅ 好的做法:使用枚举或整数作为键,避免字符串比较
public enum BulletType
{
Standard,
Heavy,
Explosive
}
public class FastBulletPoolSystem : AbstractObjectPoolSystem<BulletType, Bullet>
{
protected override Bullet Create(BulletType key) => key switch
{
BulletType.Standard => new Bullet(),
BulletType.Heavy => new Bullet(),
BulletType.Explosive => new Bullet(),
_ => throw new ArgumentException()
};
}
```
### 3. 批量操作
```csharp
// ✅ 好的做法:批量获取和释放对象
public class BatchPoolSystem : AbstractObjectPoolSystem<string, PooledObject>
{
public List<PooledObject> AcquireBatch(string key, int count)
{
var objects = new List<PooledObject>(count);
for (int i = 0; i < count; i++)
{
objects.Add(Acquire(key));
}
return objects;
}
public void ReleaseBatch(string key, IEnumerable<PooledObject> objects)
{
foreach (var obj in objects)
{
Release(key, obj);
}
}
}
```
## 注意事项
1. **对象状态管理**:确保 `OnRelease` 方法彻底重置对象状态,避免状态污染
2. **对象引用**:不要在放回对象池后继续持有对象引用
3. **线程安全**:对象池本身不是线程安全的,如需多线程访问,需要自行加锁
4. **内存泄漏**:确保所有获取的对象最终都放回池中
5. **对象池大小**:合理设置对象池大小,避免内存浪费或频繁创建
## 相关包
- [`system`](./system.md) - 对象池系统继承自 AbstractSystem
- [`architecture`](./architecture.md) - 在架构中注册对象池系统
---
**许可证**: Apache 2.0