您的位置:首页 > 移动开发 > Cocos引擎

cocos2dx内存管理机制学习笔记,源码分析

2017-11-08 11:12 639 查看
cocos2dx面试时最容易考的问题就是内存管理,我自己都被问的烦了,本文分析透彻,源码详尽,可以避免在这个问题上失分

cocos2dx的内存管理采用引用计数的策略,百度百科的引用计数解释如下:



通过源代码分析,作出以下总结:

1.Ref类中的_referenceCount成员变量用作引用计数

protected:
/// count of references
unsigned int _referenceCount;

2.Ref的构造函数为_referenceCount赋值为1

Ref::Ref()
: _referenceCount(1) // when the Ref is created, the reference count of it is 1

3.retain() 执行++_referenceCount,release()执行--_referenceCount,并且当_referenceCount ==0时,释放对象.

void Ref::retain()
{
++_referenceCount;
}
void Ref::release()
{
--_referenceCount;
if (_referenceCount == 0)
{
delete this;
}
}

4.autorelease()会在自动释放池中,添加一个对象(向量尾部插入新对象),AutoreleasePool类中,使用向量容器vector<Ref*> _managedObjectArray保存对象。

Ref* Ref::autorelease()
{
PoolManager::getInstance()->getCurrentPool()->addObject(this);
return this;
}
void AutoreleasePool::addObject(Ref* object)
{
_managedObjectArray.push_back(object);
}
std::vector<Ref*> _managedObjectArray;
5.通过create()创建的对象,会执行new(),init(),autorelease()几个函数,即对象被放入自动释放池,这类对象若不addchild()会在下一帧释放,若想保留可手动retain(),不需要时手动release()

Scene* Scene::create()
{
Scene *ret = new (std::nothrow) Scene();
if (ret && ret->init())
{
ret->autorelease();
return ret;
}
else
{
CC_SAFE_DELETE(ret);
return nullptr;
}
}

6.导演类的mainLoop()执行drawScene()画完一帧后,执行 PoolManager::getInstance()->getCurrentPool()->clear();clear()有2个功能:

(1)

std::vector<Ref*> releasings;
releasings.swap(_managedObjectArray);


用新向量releasings和向量_managectArray互换,将_managedObjectArray内容清空,长度清0,这么做是为了让自动释放池中的对象只自动执行一次release()判断是否释放

(2)

for (const auto &obj : releasings)
{
obj->release();
}


遍历自动释放池中的对象逐一调用一次release(),完整代码如下:

void DisplayLinkDirector::mainLoop()
{
if (_purgeDirectorInNextLoop)
{
_purgeDirectorInNextLoop = false;
purgeDirector();
}
else if (_restartDirectorInNextLoop)
{
_restartDirectorInNextLoop = false;
restartDirector();
}
else if (! _invalid)
{
drawScene();//画一帧

// release the objects
PoolManager::getInstance()->getCurrentPool()->clear();
}
}
void AutoreleasePool::clear()
{
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
_isClearing = true;
#endif
std::vector<Ref*> releasings; releasings.swap(_managedObjectArray);
for (const auto &obj : releasings) { obj->release(); }
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
_isClearing = false;
#endif
}
7.addChild(Node *child)会执行child->retain();removechild()会执行child->release();

void Node::addChild(Node *child)
{
CCASSERT( child != nullptr, "Argument must be non-nil");
this->addChild(child, child->_localZOrder, child->_name);
}
void Node::addChild(Node* child, int localZOrder, const std::string &name)
{
CCASSERT(child != nullptr, "Argument must be non-nil");
CCASSERT(child->_parent == nullptr, "child already added. It can't be added again");

addChildHelper(child, localZOrder, INVALID_TAG, name, false);
}
void Node::addChildHelper(Node* child, int localZOrder, int tag, const std::string &name, bool setTag)
{
if (_children.empty())
{
this->childrenAlloc();
}

this->insertChild(child, localZOrder);
//以下省略
}
void Node::insertChild(Node* child, int z)
{
_transformUpdated = true;
_reorderChildDirty = true;
_children.pushBack(child);
child->_localZOrder = z;
}
void pushBack(T object)
{
CCASSERT(object != nullptr, "The object should not be nullptr");
_data.push_back( object );
object->retain();
}


8.当对象的指针作为形参时,函数体内需retain()形参 (形参被其他指针保留了,所以需retain),

release被赋值指针(被赋值指针不需要使用原先指向的对象了,所以需release),再赋值.

void testFun(Ref* obj1)
{
obj1->retain();
obj2->release();
obj2 = obj1;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: