一、对象池的好处
对于一些需要频繁创建删除的对象变量,可以减少创建删除的性能消耗,以及读写消耗,同时也方便管理。
二、对象池的原理
对象池的实现需要三个脚本:
一个对象池脚本,一个对象管理脚本,一个对象脚本;
步骤:
1.通过对象管理类,从 对象池类 获取一个对象类实例,如果没有就创建一个,并返回对象引用。
2.获得引用之后,就可以直接使用对象的成员函数【没有对象池的话,这就是第一步】
3.当对象使用周期结束,仅清空数据,不删除对象,将其放入对象池中,等待下一次获取。
三、类定义
(1)对象池脚本 ObjectPool.h
// 这里声明模板类, 这样只要满足固定几个函数,什么对象类都可以用来创建对象池
// 第二个参数 num 是 一个对象块包含的对象节点的数量
template<class T, int num>
class ObjectPool
{
// 对象池类,里面声明了两个类,多个对象节点组成一个对象块,多个对象块组成一个对象池
// 对象节点类
class ObjectNode
{
T obj; // 模板类对象
ObjectNode * next_node; // 下一个对象节点
bool isFree; // 是否空闲
public:
ObjectNode():next_node(NULL), isFree(true){
obj = T();
}
}
// 对象块类
class ObjectBlock
{
ObjectBlock *next_block; // 下一个对象块
ObjectNode *nodes; // 对象节点数组【多个节点组成一个对象块】
ObjectBlock(int num):next_block(NULL){ // num 由模板参数传入
nodes = new ObjectNode[num];
}
~ObjectBlock(){
delete [] nodes;
}
}
private:
ObjectBlock * m_fristBlock; // 第一个对象块
ObjectBlock * m_curBlock; // 最后一个对象块
ObjectNode * m_firstFreeNode; // 第一个空闲对象节点 【注意:空闲对象节点贯穿多有对象块,使用完后就插入链表末尾】
ObjectNode * m_lastFreeNode; // 最后一个空闲对象节点【空闲链表末尾】
int usingObjects; // 当前使用的对象节点数量
Mutex m_lock; // 对象池数据锁
}
(2)对象管理 PacketMgr.h
class CPacketMgr
{
// 创建 对象管理 对象
inline static CPacketMgr & instance(){
static CPacketMgr s_inst; // 创建静态实例(static 保证 只创建一次)
return s_inst;
}
// 创建 对象池 对象
inline static ObjectPool<MsgPacket, 100> &PacketPool(){ // 创建并获取对象池(保证只存在一个对象池)
static ObjectPool<MsgPacket, 100> s_inst;
return s_inst;
}
// 获取 对象节点 对象
inline static MsgPacket & Allocate(){
return *(PacketPool().Allocate()); // 获取对象池实例,然后通过对象池实例 分配对象节点
}
// 释放 对象节点 对象
inline void Free(MsgPacket &msg){
PacketPool().Free(msg);
}
// 快速 获取 对象节点 对象
inline static MsgPacket & FastAllocate(){
return *(PacketPool().FastAllocate()); // 获取对象池实例,然后通过对象池实例 分配对象节点
}
// 快速 释放 对象节点 对象
inline void FastFree(MsgPacket &msg){
PacketPool().FastFree(msg);
}
}
#define PacketMgr CPacketMgr::instance() // 相当于 PacketMgr 就是实例
(3) 对象 MsgPacket.h
class MsgPacket
{
MsgPacket(){}
~MsgPacket(){}
// 重置数据(回收对象节点时调用)
void destory()
{
// 清空元素,但是空间不清除! 比如 不改变或者调成默认值 vector的 capacity, 然后 vector::clear()
}
void helloworld()
{
cout<<"helloworld"<<endl;
}
}
四、对象池使用(纯手写没测试,思路没问题)
#include<iostream>
#include<vector>
#include "ObjectPool.h"
#include "MsgPacket.h"
#include "PackrtMgr.h"
using namespace std;
int main()
{
MsgPacket &pkt = PacketMgr.Allocate(); // 这部包含了创建 对象管理类实例,创建对象池类实例,创建对象类实例。
// 调用对象函数
pkt.helloworld();
//释放对象 【注意,这里的释放是放入对象池中,并没有清空内存】
PackMgr.Free(pkt);
return 0;
}
五、总结
对象池就是把对象的创建和释放进行集中管理,从而降低创建删除消耗,且不影响对象类实现。
而且只要对象类满足固定函数,就可以创建对象池,用法很方便。