基于Handle的资源管理方案,第一时间想到的应该是Windows了,但是真正想让我实施这个方案的,是《游戏编程精粹1》里面的游戏资源管理篇章的给出的方案。在《游戏编程精粹1》里面的资源标示Handle类,是一个极为简单的32位int类型,分为前16位的index和后16位的magic num,magic num主要是用来用作资源的校验的,在获取实例资源和删除实例资源的时候,都会校验一次。这两个数据合成一个int32用来标示唯一的资源。
union { enum { MAX_BITS_INDEX = 16, MAX_BITS_MAGIC = 16, MAX_INDEX = (1 << MAX_BITS_INDEX) - 1, MAX_MAGIC = (1 << MAX_BITS_MAGIC) - 1, }; struct { unsigned mIndex : MAX_BITS_INDEX; unsigned mMagic : MAX_BITS_MAGIC; }; uint mHandle; };
当然,这个Handle在书里面是定义成模板了,主要还是转为C++的习惯,变成一种强类型的标示吧,不同资源类型不能相互赋值和转化。
接来下是定义HandleManager,这个类也是一个模板,就跟名字一样,是用来管理Handle的,里面有两个vector,一个是保存正在使用的资源的vector,一个是删除资源后放入的free vector,当用户需要新建一个Handle的时候,会优先从free vector里面查找空的Handle,重新指向新的资源。
但是这个Handle的指向资源实例数组的index是不会变的,会变的只是magic num。总的来说,Handle还是变了。
template<typename DATA, typename RESHANDLE> DATA * ResHandleMgr<DATA, RESHANDLE>::acquire(RESHANDLE &handle) { uint index; if (mFreeSlots.empty()) { index = mMagicNums.size(); handle.init(index); DATA *pData = new DATA(); mUserVec.push_back(pData); mMagicNums.push_back(handle.getMagic()); } else { index = mFreeSlots.back(); // init后,magic num 会加一 handle.init(index); mFreeSlots.pop_back(); mMagicNums[index] = handle.getMagic(); } //return (mUserVec.begin() + index); UserVec::iterator iter = mUserVec.begin() + index; return *iter; }
这个大体就是《游戏编程精粹1》里面的引擎资源管理方案了,要保存资源很简单,持有Handle就行了,要获取和删除资源直接用Handle就行了。但是,估计大家也看来出什么问题了,资源没有自动释放的机制!!!!!!!
于是,我在Handle类里面加了个变量,用来作为引用计数,这里暂时没有引入智能指针(这个引用计数优化的方法应该可以加入一个内存池)
private: union { enum { MAX_BITS_INDEX = 16, MAX_BITS_MAGIC = 16, MAX_INDEX = (1 << MAX_BITS_INDEX) - 1, MAX_MAGIC = (1 << MAX_BITS_MAGIC) - 1, }; struct { unsigned mIndex : MAX_BITS_INDEX; unsigned mMagic : MAX_BITS_MAGIC; }; uint mHandle; }; //保存引用计数 uint *mpRefCount;
在Handle释放的时候,handle.release(),在Handle赋值的时候,handle.addRef,当(*mpRefCount) == 0的时候,就可以释放资源资源了。
一开始的时候,将引用计数设置为static std::map<int, int>(前面一个int表示Handle,后面一个表示引用次数),后来发现效率实在太低,于是改为 uint *mpRefCount指针这种形式,帧数上升了20 FPS左右。。。
这个Handle类大体长这个样子的,基本也可以实现资源的自动释放机制了
template<typename ResType> class ENGINE_DLL ResHandle { public: ResHandle(); ResHandle(const ResHandle &handle); ~ResHandle(); void init(uint index); uint getIndex() const; uint getMagic() const; uint getHandle() const; bool isNull() const; operator uint() const; void addRef(); void release(); ResHandle &operator =(ResHandle handle) { mHandle = handle.getHandle(); if (handle.isNull() == false) { assert(handle.mpRefCount != 0); if (isNull() == false && mpRefCount) { release(); if (mpRefCount != 0) assert(mpRefCount == handle.mpRefCount); } } mpRefCount = handle.mpRefCount; addRef(); return *this; } private: union { enum { MAX_BITS_INDEX = 16, MAX_BITS_MAGIC = 16, MAX_INDEX = (1 << MAX_BITS_INDEX) - 1, MAX_MAGIC = (1 << MAX_BITS_MAGIC) - 1, }; struct { unsigned mIndex : MAX_BITS_INDEX; unsigned mMagic : MAX_BITS_MAGIC; }; uint mHandle; }; uint *mpRefCount; }; template<typename ResType> ResHandle<ResType>::ResHandle(const ResHandle &handle) : mpRefCount(0) { mHandle = handle.getHandle(); mpRefCount = handle.mpRefCount; addRef(); } template<typename ResType> ResHandle<ResType>::~ResHandle() { release(); } template<typename ResType> void ResHandle<ResType>::release() { if (mHandle != 0) { --(*mpRefCount); if (*mpRefCount == 0) { //std::cout << "need delete !!!!" << std::endl; //delete operator //后面加入 Log::getInstancePtr()->logMsg("release res handle = %d", mHandle); SAFE_DELETE(mpRefCount); } } } template<typename ResType> void ResHandle<ResType>::addRef() { if (mHandle != 0) { ++(*mpRefCount); } } template<typename ResType> ResHandle<ResType>::ResHandle() : mHandle(0), mpRefCount(0) { } template<typename ResType> void ResHandle<ResType>::init(uint index) { assert(isNull()); assert(index <= MAX_INDEX); static uint sAutoMagic = 0; if (++sAutoMagic > MAX_MAGIC) { sAutoMagic = 1; } mIndex = index; mMagic = sAutoMagic; if (mpRefCount == 0) { mpRefCount = new uint; } *mpRefCount = 1; } template<typename ResType> ResHandle<ResType>::operator uint() const { return mHandle; } template<typename ResType> bool ResHandle<ResType>::isNull() const { return !mHandle; } template<typename ResType> uint ResHandle<ResType>::getHandle() const { return mHandle; } template<typename ResType> uint ResHandle<ResType>::getMagic() const { return mMagic; } template<typename ResType> uint ResHandle<ResType>::getIndex() const { return mIndex; } //------------------------------------------------------------------- template < typename Tag> inline bool operator != (ResHandle<Tag> l, ResHandle<Tag> r) { return (l.getHandle() != r.getHandle()); } template < typename Tag> inline bool operator == (ResHandle<Tag> l, ResHandle<Tag> r) { return (l.getHandle() == r.getHandle()); }