Cocos2d-x 内存管理与数据结构
引用计数
Cocos采用的是引用计数的方式管理内存,Cocos会记录堆上每个对象被引用的次数,当引用次数为0时则自动释放内存。
Ref类
为了实现对类引用次数的管理,Cocos的类都继承了Ref类。
class CC_DLLRef
{
public:
voidretain(); //增加引用计数,当需要保存使用对象时,需要调用该函数增加引用计数
voidrelease(); //减少引用计数,当引用计数减少到0时则时会释放内存
Ref*autorelease(); //将内存加入自动释放内存池,下一次Application::run()的循环会调用一次对象的Release函数
unsignedintgetReferenceCount() const;//获取引用次数
virtual~Ref(); //虚析构函数保证派生类的析构函数被调用到
protected:
Ref();//将构造函数设为保护属性,就无法直接实例化Ref类,new Ref()将报错
protected:
unsignedint_referenceCount;//记录引用的次数
friendclassAutoreleasePool;
};
AutoreleasePool
为了实现内存的自动释放AutoreleasePool创建了内存池,内存池会记录所有要自动释放的内存。
class CC_DLLAutoreleasePool
{
public:
AutoreleasePool();
AutoreleasePool(conststd::string&name);
~AutoreleasePool();
void addObject(Ref *object);//将对象加入到自动管理内存池
voidclear(); //清理内存
boolcontains(Ref* object)const;//对象是否在内存池中
voiddump(); //将内存池中的内对象信息输出到日子,方便调试
private:
std::vector<Ref*>_managedObjectArray;
std::string_name;
};
AutoreleasePool内存的释放
Main函数调用的Run函数的循环调用了director->mainLoop(),其每次绘制完后会清理内存
void DisplayLinkDirector::mainLoop()
{
if(_purgeDirectorInNextLoop){
_purgeDirectorInNextLoop= false;
purgeDirector();
}
elseif(_restartDirectorInNextLoop){
_restartDirectorInNextLoop= false;
restartDirector();
}
elseif(! _invalid)
{
drawScene();
//清理内存,对AutoreleasePool中的每个对象掉Ref::release函数
PoolManager::getInstance()->getCurrentPool()->clear();
}
}
引用内存的使用
当new一个对象后引用计数为1,然后调用Ref::autorelease加入到自动管理内存池,对象会在下一次主循环时调用Ref::release。如果需要保存对象一直使用则需要调用一次Ref::retain函数增加引用计数。例如:
//内部会调用 autorelease函数,create函数见下方代码
auto sprite = Sprite::create("HelloWorld.png");
this->addChild(sprite, 0);//内部会调用Ref::retain函数增加引用计数
Sprite* Sprite::create(const std::string& filename)
{
Sprite *sprite = new (std::nothrow) Sprite();
if (sprite && sprite->initWithFile(filename))
{
sprite->autorelease();
return sprite;
}
CC_SAFE_DELETE(sprite);
return nullptr;
}
为了方便和统一create的定义函数,Cocos提供了相CREATE_FUNC宏,在类中加入该宏及定义了create函数。
#defineCREATE_FUNC(__TYPE__) \
static__TYPE__* create() \
{\
__TYPE__ *pRet = new(std::nothrow)__TYPE__(); \
if (pRet&& pRet->init()) \
{ \
pRet->autorelease();\
returnpRet; \
} \
else \
{ \
deletepRet; \
pRet = nullptr;\
returnnullptr;\
} \
}
例如:
classHelloWorld: public cocos2d::Layer { public: virtual boolinit(); void menuCloseCallback(cocos2d::Ref*pSender); //定义静态create函数 CREATE_FUNC(HelloWorld) }; auto layer= HelloWorld::create();//CREATE_FUNC宏定义的函数 scene->addChild(layer);
Vector类
Cocos中Vector类是对C++ STL中的std::vector进行了一层封装,其只有一个变量 std::vector<T>_data;之所以要重新封装一层,是为了实现对引用计数内存的管理。
当向_data数组中添加数据时其会对调用对象的Ref:: retain函数增加引用计数,从_data中删除数据时会调用Ref::release函数减少引用计数释放释放内存。
例如pushback函数和popBack函数
voidpushBack(T object)
{
CCASSERT(object != nullptr,"The object should not be nullptr");
_data.push_back( object );
object->retain();//增加引用计数
}
voidpopBack()
{
CCASSERT(!_data.empty(), "no objects added");
autolast= _data.back();
_data.pop_back();
last->release();//减少引用计数释放内存
}
Map类
cocos2d::Map类是使用std::unordered_map作为底层结构的关联式容器。在关联式容器的基础上进行封装实现对引用计数内存的自动管理。