游戏中的对象缓存池

   在游戏编程时,每个关卡都要创建大量的对象,例如NPC,树,草,地形等,而有些对象需要有游戏中实时创建,比如爆炸效果,子弹。给游戏对象分配内存本来就是比较耗费时间的,如果采用传统的new 和delete的话,可能会使得游戏的实时性降低。因此可以采用对象池的方法。即先根据关卡估计会用到对象数量,在关卡开始时先分配好需要的对象数量缓存起来,以后直接使用这些缓存的对象就OK了,当游戏关卡结束时,清除对象池。

    本文采用了模版方法,参照了《面向对象游戏开发--julian Gold》第七章的内容。对于一种对象的缓存池类来说,它在程序中只应该有一个对象。因为为一种对象创建两个或多个缓存池根本就没有必要,反而会增加代码的复杂度。因此我采用了单件模式。

    那么怎样将对象缓存起来呢,我们只需要为每个类重载操作符 new 和 delete 即可,当用户new 一个对象时,我们从缓存池里拿出一个事先分配好的对象,返回给用户即可。当用户调用 delete时,我们将请求删除的对象放入缓存池,方便下次用户调用new时使用。

 

内存池代码如下:

 //内存池,2009.12.24 //缓存一定数量的对象,使内存分布更快 //from neo //参考了<<面向对象游戏开发 ----julian gold>> //使用了单件模式 //用法示例 /* class A { public: NEWCLASS(A); DELETECLASS(A); BUFFERSIZEMEMBER(A); }; SETBUFFERSIZE(A,size) */ #pragma once #include #include #include namespace Neo { template class MemPool { public: static MemPool& Instance(); //返回单件实例 public: void SetBufferSize(unsigned int size); //设置缓冲池大小 T* Allocate(); //分配 void Free(T* pT); //释放 void Clear(); //清除所有的缓存对象 private: std::vector m_listBuffer; //缓存对象 std::vector m_listToAllocate; //未分配的对象 private: //辅助类, //删除缓存值的算法 template struct DeleteAlgorithm { void operator ()(T* pT){::delete pT;} }; //新建算法 template struct NewAlgorithm { void operator ()(T* pT){pT = ::new T;} }; private: //不允许用户自己定义内存池 MemPool(){} ~MemPool(void)//最后清除所有的缓存对象 {Clear();} MemPool(const MemPool& other); }; //成员函数实现 template inline MemPool& MemPool::Instance() { static MemPool anInstance; return anInstance; } //设置缓存池大小 template inline void MemPool::SetBufferSize(unsigned int size) { m_listBuffer.resize(size); //为什么这样分配的调用是全局的delete呢??vs2008下测试 //std::for_each(&m_listBuffer[0],&m_listBuffer[m_listBuffer.size()-1],NewAlgorithm()); for (unsigned int i=0;i inline T* MemPool::Allocate() { //内存已经分配完了, //以后可以考虑重写这个部分,例如动态增长 assert(!m_listToAllocate.empty() &&"out of mem"); T* pT = m_listToAllocate.back(); m_listToAllocate.pop_back(); return pT; } //释放对象 template inline void MemPool::Free(T* pT) { //确保删除的对象在缓存中 assert(std::find(m_listBuffer.begin(),m_listBuffer.end(),pT) != m_listBuffer.end() && "object to free is not exist!!"); //确保只删除一次 assert(std::find(m_listToAllocate.begin(),m_listToAllocate.end(),pT) == m_listToAllocate.end() &&"object has deleted already!!"); m_listToAllocate.push_back(pT); } //清除缓存池内容 template inline void MemPool::Clear() { std::for_each(m_listBuffer.begin(),m_listBuffer.end(),DeleteAlgorithm()); m_listBuffer.clear(); } } //一些宏定义,方便使用 //定义重载new #define NEWCLASS(className) / void* operator new(size_t)/ {/ return Neo::MemPool::Instance().Allocate();/ } //定义重载delete #define DELETECLASS(className)/ void operator delete(void* p)/ {/ Neo::MemPool::Instance().Free(reinterpret_cast(p));/ } //设置缓存池大小静态成员函数 #define BUFFERSIZEMEMBER(className) / static bool SetBufferSize(unsigned int size)/ {/ Neo::MemPool::Instance().SetBufferSize(size);/ return true;/ } #define SETBUFFERSIZE(className,size) static bool initial##className = className::SetBufferSize(size);

 

测试程序:请注意debug模式与release模式的区别(Release模式下比较快)

 

#include #include #include #include "MemPool.h" #pragma comment(lib,"winmm.lib") using namespace std; //在写游戏代码时,可以估算一个关卡所需的对象数量,设置一个合适的缓存值 const int bufferSize = 20; class TestWithAllocated { public: NEWCLASS(TestWithAllocated); DELETECLASS(TestWithAllocated); BUFFERSIZEMEMBER(TestWithAllocated); }; SETBUFFERSIZE(TestWithAllocated,bufferSize); class Derived : public TestWithAllocated { public: NEWCLASS(Derived); DELETECLASS(Derived); BUFFERSIZEMEMBER(Derived); public: void fun(){cout << "hello" << endl;} }; SETBUFFERSIZE(Derived,bufferSize); class TestWithOutAllocated { }; template void Allocate(std::vector& p,int size) { for (int i=0;i void DeAllocate(std::vector& p,int size) { for (int i=0;i> testSize; std::vector pWA(bufferSize); std::vector pWOA(bufferSize); //计算测试时间 DWORD start = timeGetTime(); //采用了内存池的对象创建测试 for (int i=0;i(pWA,bufferSize); DeAllocate(pWA,bufferSize); } DWORD end = timeGetTime(); cout << " test with buffer time is: " << end - start << endl; //未采用内存池的对象创建测试 start = timeGetTime(); for (int i=0;i(pWOA,bufferSize); DeAllocate(pWOA,bufferSize); } end = timeGetTime(); cout << " test without buffer time is: " << end - start << endl; //采用了内存池另一组对象创建测试 std::vector pW(bufferSize); start = timeGetTime(); for (int i=0;i(pW,bufferSize); DeAllocate(pW,bufferSize); } end = timeGetTime(); cout << " test with buffer time is: " << end - start << endl; return 0; }

 

 

测试结果:

在我的电脑上当输入测试数量为100000时

采用内存池分配的对象用时70

未采用内存池根本的对象用时565

以上测试在Release模式下完成,因为在debug模式下,我采用了一些算法,确保分配不会出错。所以效率很低

你可能感兴趣的:(游戏中的对象缓存池)