Apollo 技术文档Apollo 技术文档
指南
  • 架构概述
  • BigWorld 架构深度解析
  • BigWorld 进程架构与玩家生命周期
  • AOI九宫格系统详解
  • AOI广播与消息去重
  • Base 模块
  • Core 模块
  • Runtime 模块
  • Data 模块
  • Network 模块
  • /modules/actor.html
  • Game 模块
  • BigWorld 模块
服务器应用
API 参考
QA
GitHub
指南
  • 架构概述
  • BigWorld 架构深度解析
  • BigWorld 进程架构与玩家生命周期
  • AOI九宫格系统详解
  • AOI广播与消息去重
  • Base 模块
  • Core 模块
  • Runtime 模块
  • Data 模块
  • Network 模块
  • /modules/actor.html
  • Game 模块
  • BigWorld 模块
服务器应用
API 参考
QA
GitHub
  • MMORPG 架构 QA

Q58: 对象池是什么?如何设计?

核心结论

对象池的价值不在于“避免写 new/delete”,而在于降低高频对象创建和回收带来的抖动与碎片成本。

它适合:

  • 生命周期短
  • 类型相对稳定
  • 创建销毁非常频繁

如果对象生命周期复杂、数量不可预测或状态清理困难,对象池反而可能制造更多问题。

一、对象池真正解决什么问题

主要是这几类:

  • 高频分配释放开销
  • 内存碎片
  • 延迟抖动
  • 热路径对象反复构造析构

所以对象池更像一种性能稳定化手段,而不是通用设计模式。

二、哪些对象适合池化

常见适合池化的包括:

  • 网络包对象
  • 临时事件对象
  • 子弹、投射物、特效实例
  • 某些固定大小消息节点

这些对象的共同点是:

  • 数量大
  • 使用频繁
  • 结构比较简单

三、哪些对象不适合池化

通常包括:

  • 状态非常复杂的大对象
  • 生命周期很长的对象
  • 稀疏创建的对象
  • 释放后很难彻底重置的对象

如果重置成本比新建还高,对象池就没什么意义。

四、对象池设计的关键点

1. 获取和归还必须足够轻

如果池本身需要重锁、复杂查找或大量校验,收益会被吃掉。

2. 状态清理要可靠

池化对象最大风险之一是脏状态残留。

每次归还或再次借出时,必须保证对象回到可预测状态。

3. 容量策略要明确

需要先定义:

  • 初始容量
  • 最大容量
  • 池空时是扩容还是降级到普通分配

不能只是假设对象数量永远刚好。

五、对象池和内存池不是一回事

对象池关注“对象实例复用”,内存池更关注“分配内存块”。

两者经常一起使用,但目标不同:

  • 对象池解决构造和对象复用问题
  • 内存池解决底层分配问题

不要把它们混成一个概念。

六、多线程场景下要特别谨慎

对象池一旦跨线程共享,就会遇到:

  • 锁竞争
  • ABA 风险
  • 归还到错误线程
  • cache line 抖动

所以高并发场景里常见做法是:

  • 线程本地池
  • 分片池
  • 中央池加本地缓存

这通常比一把全局锁的池更稳。

七、工程上更稳妥的落地方式

常见做法是:

  • 先通过 profiling 找出高频短命对象
  • 只对这些对象池化
  • 明确 reset 规则和容量上限
  • 保留超限回退路径

这样收益更可控,也更容易验证。

八、常见误区

1. 只要性能有问题就上对象池

不对。对象池只适合一部分分配热点。

2. 池化对象越多越好

池太大也会浪费内存,还会隐藏真实生命周期问题。

3. 对象归还后不清理,下次覆盖就行

这会制造极难定位的脏状态 bug。

参考资料

  • 对象池、arena 和高频分配优化相关实践资料
在 GitHub 上编辑此页
最后更新: 3/20/26, 6:06 AM
贡献者: cuihairu