简单对象池管理器实现

本篇文章主要介绍一下「对象池管理器」的实现思路和步骤

背景

我们在处理游戏的视觉表现上,当有许多视图重复的绘制和移除时,系统需要频繁的进行创建和销毁,造成压力。
另一方面,如果创建和销毁没有进行很好的管理,很可能出现内存泄漏的情况。

例如三消游戏,游戏场景有许多消除元素,当重复消除元素时,会将消除的元素进行销毁,再将新的元素创建并添加到舞台上。如果频繁的消除,这个过程将进行非常多次。

鱼与熊掌不可兼得,但「对象池模式」的出现,却能够在减少创建和销毁压力的同时,又能很好的管理内存。

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 类图结构

20210917153707

时序图

从池子中取出对象

20210917153132

将对象释放回池子

20210917153242

架构的取舍

  • 对象池对象没有使用继承的方式实现,而是采用接口的方式。
    优点是可以做到通用性,不依赖当前框架的数据结构,跨框架的使用,复用性和移植性强。
    缺点是没有通用的父类方法,对于初始化和释放都要自己实现。

  • 为了更好的扩展性,并没有针对池子上限进行限制,也没有自动释放对象池的机制,需要使用者自行管理。

  • 由于池子存储的 key 依赖于对象本身的类名,当进行代码混淆的时候,会出现类名重复的情况,从而导致池子重复,出现异常。
    解决方案是对象池对象实现一个静态属性 className , 用于生成池子 key 。并且通过在对象池获取和释放对象时,传入的构造类型参数中添加静态属性 className 的检测。

使用场景

这个模式广泛应用于可见的事物上,比如游戏实体和视觉效果。
但是它也可在不那么视觉化的数据结构上使用,比如正在播放的声音。
在以下情况中使用对象池:

  • 需要频繁创建和销毁对象。
  • 数量受限的资源。
  • 创建成本高昂的对象。

注意事项

  • 清除池子的时机
    池子可能在不需要的对象上浪费内存,所以使用时,如果发现后续场景不会从池子中获取对象,请主动清除。

  • 池子上限
    默认并未设置池子上限,需要使用者根据游戏的需求设置。当池子太小时,很明显需要调整。但是也要小心确保池子没有太大。

  • 对象池对象的释放
    请确保对象池对象在释放的时候,除了池子以外,没有其他地方对其的引用,也没有监听事件或者保持对全局对象的引用。
    不然就算清除了池子,对象池对象也不会在内存中释放,反而会造成内存泄漏。

参考资料

对象池模式
WIKI
Android Pools 源码

本文作者:雪糕
本文地址: https://blooddot.cool/posts/9c88a4d3/
版权声明:转载请注明出处!