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

来源:互联网 发布:桩冠修复 知乎 编辑:程序博客网 时间:2024/06/08 11:35

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;}


原创粉丝点击