简单对象池管理器实现
背景
我们在处理游戏的视觉表现上,当有许多视图重复的绘制和移除时,系统需要频繁的进行创建和销毁,造成压力。
另一方面,如果创建和销毁没有进行很好的管理,很可能出现内存泄漏的情况。
例如三消游戏,游戏场景有许多消除元素,当重复消除元素时,会将消除的元素进行销毁,再将新的元素创建并添加到舞台上。如果频繁的消除,这个过程将进行非常多次。
鱼与熊掌不可兼得,但「对象池模式」的出现,却能够在减少创建和销毁压力的同时,又能很好的管理内存。
WIKI 对象池模式的定义
对象池(英语:object pool pattern)是一种设计模式。一个对象池包含一组已经初始化过且可以使用的对象,而可以在有需求时创建和销毁对象。池的用户可以从池子中取得对象,对其进行操作处理,并在不需要时归还给池子而非直接销毁它。这是一种特殊的工厂对象。
目的
提供一个通用的对象池管理器,来管理所有池子数据,在提供外部方法用于获取和释放对象到池子内,并调用对象的初始化和释放的方法。
目标对象需要实现指定的对象池对象接口,用于初始化和释放。
术语与缩略语
| name | meaning | description |
| —- | ——- | ———– |
| PoolMgr
| 对象池管理器 | 用于创建和回收对象, 管理对象池 |
| IPoolData
| 池子接口 | 用于存储对象池对象的数据实现的接口,以下简称池子 |
| IPoolObject
| 对象池对象接口 | 对象池内对象需要实现的接口 |
详细设计
功能说明
获取对象
当需要创建新对象时,从管理器要一个,查找是否存在指定池子对象。
当不存在池子或者池子数量小于等于 0 时,创建一个对象并返回。
否则,从池子中拿出一个对象。
取出的对象会执行onAcquire
方法进行初始化。释放对象
当对象不需要时,将对象放回到池子中,查找是否存在指定池子对象。
当不存在池子时,创建一个池子对象。
否则,获取该池子对象。
将对象放回到池子中,放回的对象会执行onRelease
方法进行回收。设置池子上限
调用管理器的setMaxPoolSize
方法设置指定池子的数量上限。
当不存在池子时,会自动创建一个。清除池子
调用管理器的clear
方法可以清除制定池子的数据。
类和接口
PoolMgr 对象池管理器
通过创建一个全局的单例,用来管理对象及池子的创建和回收
方法一览:
- acquire 取出一个对象池对象(如果不存在该对象的池子,或者池子内不存在数据,则创建一个新的对象。)
- release 释放一个对象回池子中(如果不存在该对象的池子,则创建一个新的池子。如果设置了池子对象数量上限,则超出数量后不回收到池子内)
- setMaxPoolSize 设置指定池子最大对象数量
- clear 清除指定池子数据
IPoolData 池子接口
通过存储对象池对象的数据集合接口
方法一览:
- poolObjects 对象池对象数据
- maxPoolSize 当前池子对象数量上限
IPoolObject 对象池对象接口
对象池内对象需要实现的接口
方法一览:
- poolKey 对应的池子 key,用于回收时查找池子
- onAcquire 当从池子取出时,初始化方法
- onRelease 当释放回池子时,回收的方法
UML 类图结构
时序图
从池子中取出对象
将对象释放回池子
架构的取舍
对象池对象没有使用继承的方式实现,而是采用接口的方式。
优点是可以做到通用性,不依赖当前框架的数据结构,跨框架的使用,复用性和移植性强。
缺点是没有通用的父类方法,对于初始化和释放都要自己实现。为了更好的扩展性,并没有针对池子上限进行限制,也没有自动释放对象池的机制,需要使用者自行管理。
由于池子存储的
key
依赖于对象本身的类名,当进行代码混淆的时候,会出现类名重复的情况,从而导致池子重复,出现异常。
解决方案是对象池对象实现一个静态属性className
, 用于生成池子key
。并且通过在对象池获取和释放对象时,传入的构造类型参数中添加静态属性className
的检测。
使用场景
这个模式广泛应用于可见的事物上,比如游戏实体和视觉效果。
但是它也可在不那么视觉化的数据结构上使用,比如正在播放的声音。
在以下情况中使用对象池:
- 需要频繁创建和销毁对象。
- 数量受限的资源。
- 创建成本高昂的对象。
注意事项
清除池子的时机
池子可能在不需要的对象上浪费内存,所以使用时,如果发现后续场景不会从池子中获取对象,请主动清除。池子上限
默认并未设置池子上限,需要使用者根据游戏的需求设置。当池子太小时,很明显需要调整。但是也要小心确保池子没有太大。对象池对象的释放
请确保对象池对象在释放的时候,除了池子以外,没有其他地方对其的引用,也没有监听事件或者保持对全局对象的引用。
不然就算清除了池子,对象池对象也不会在内存中释放,反而会造成内存泄漏。
参考资料
本文作者:雪糕
本文地址: https://blooddot.cool/posts/9c88a4d3/
版权声明:转载请注明出处!