cocos2dx 3.x 自学笔记 <三> cocos2dx 2.x 3.x 内存管理机制

转载请注明来自 _鞋男blog:http://blog.csdn.net/wushao126/article/details/41050605

仍然是2.x与 3.x的对比

cocos2dx 2.x:


当我们创建一个精灵的时候,都会调用精灵对象的autorelease(),

CCSprite* CCSprite::create(const char *pszFileName)
{
    CCSprite *pobSprite = new CCSprite();
    if (pobSprite && pobSprite->initWithFile(pszFileName))
    {
        pobSprite->autorelease();
        return pobSprite;
    }
    CC_SAFE_DELETE(pobSprite);
    return NULL;
}
当创建一个精灵对象的时候,
    CCSprite* sprite = CCSprite::create(s_pPathGrossini);
    CCLog("sprite->retainCount()=%d",sprite->retainCount());//output:sprite->retainCount()=1
    addChild(sprite,kTagSprite);
    CCLog("sprite->retainCount()=%d",sprite->retainCount());//output:sprite->retainCount()=2
跟踪
pobSprite->autorelease();
跳转到了
CCObject* CCObject::autorelease(void)
{
    CCPoolManager::sharedPoolManager()->addObject(this);
    return this;
}

敢说CCSprite不是CCObject的派生类!!!

有个CCPoolManager全局对象,把精灵对象加了进去

void CCPoolManager::addObject(CCObject* pObject)
{
    getCurReleasePool()->addObject(pObject);
}

形参为CCObject* ,这就已经不用管对象是不是精灵了,我们只需要记得是个CCObject对象,至于多肽神马的有RTTI机制搞定了。

继续跟进:

void CCPoolManager::addObject(CCObject* pObject)
{
    getCurReleasePool()->addObject(pObject);
}

CCAutoreleasePool* CCPoolManager::getCurReleasePool()
{
 if(!m_pCurReleasePool)
 {
 push();<pre name="code" class="cpp">        //创建一个自动释放池 并加入到释放池栈中
}

CCAssert(m_pCurReleasePool,"current auto release pool should not be null");

return m_pCurReleasePool;
}
 这里简单说明下, 
class CC_DLL CCPoolManager
{
    CCArray* m_pReleasePoolStack; 
 CCAutoreleasePool* m_pCurReleasePool;
public:
...
    friend class CCAutoreleasePool;
};
void CCPoolManager::push()
{
    CCAutoreleasePool* pPool = new CCAutoreleasePool();       //ref = 1
    m_pCurReleasePool = pPool;

    m_pReleasePoolStack->addObject(pPool);                   //ref = 2

    pPool->release();                                       //ref = 1
}

以上代码可以看出我们创建的对象被加入到一个CCArray中的一个CCAutoreleasePool中,看这

void CCAutoreleasePool::addObject(CCObject* pObject)
{
    m_pManagedObjectArray->addObject(pObject);

    CCAssert(pObject->m_uReference > 1,"reference count should be greater than 1");
    ++(pObject->m_uAutoReleaseCount);
    pObject->release(); // no ref count,in this case autorelease pool added.
}
其实在CCAutoreleasePool里也维持一个CCArray,用来存放被加入的CCObject对象,m_uReference在CCObject构造器中被初始化为1,m_uAutoReleaseCount +1了,但是autoRelease的时候未被引用,所以会被release,m_uReference被减1为0,因为到0的时候,那对象岂不是挂了,看下面代码
void ccArrayAppendObject(ccArray *arr,CCObject* object)
{
    CCAssert(object != NULL,"Invalid parameter!");
    object->retain();
	arr->arr[arr->num] = object;
	arr->num++;
}
这个全局函数式CCArray::addObject调用,在这里retain()了对象,m_uReference为2,但是我们没有引用,所以在这里release了下
void CCObject::release(void)
{
    CCAssert(m_uReference > 0,"reference count should greater than 0");
    --m_uReference;

    if (m_uReference == 0)
    {
        delete this;
    }
}
至于CCArray是什么机制,这个以后会讲到的

以上基本把retain(),release(),autorelease()讲了个遍。

接下来将引擎如果管理CCAutoreleasePool的:

int CCApplication::run(){
...
   while(1){
   ...
 if (nNow.QuadPart - nLast.QuadPart > m_nAnimationInterval.QuadPart)
 {
 nLast.QuadPart = nNow.QuadPart;
 CCDirector::sharedDirector()->mainLoop();//
 }
   ...
   }
}
CCDirector游戏引擎的管理者,这里介绍mainLoop(),顾名思义,主循环,任何系统都有它的死循环,这个也不例外。进去看看:
void CCDisplayLinkDirector::mainLoop(void)
{
    if (m_bPurgeDirecotorInNextLoop)
    {
        m_bPurgeDirecotorInNextLoop = false;
        purgeDirector();
    }
    else if (! m_bInvalid)
     {
         drawScene();
     
         // release the objects
         CCPoolManager::sharedPoolManager()->pop();        
     }
}
这个也没什么与内存有关的也就是pop(),且看pop():
void CCPoolManager::pop()
{
    if (! m_pCurReleasePool)
    {
        return;
    }

     int nCount = m_pReleasePoolStack->count();

    m_pCurReleasePool->clear();
 
      if(nCount > 1)
      {
        m_pReleasePoolStack->removeObjectAtIndex(nCount-1);

//         if(nCount > 1)
//         {
//             m_pCurReleasePool = m_pReleasePoolStack->objectAtIndex(nCount - 2);
//             return;
//         }
        m_pCurReleasePool = (CCAutoreleasePool*)m_pReleasePoolStack->objectAtIndex(nCount - 2);
    }

    /*m_pCurReleasePool = NULL;*/
}
上面说明了m_pReleasePoolStack存放的是CCAutoreleasePool对象,是个CCArray*,如果把这个CCArray看成一个栈,就将栈顶弹出,addObject会调用retain(),同理,removeObject会调用一次release(),但凡栈内m_uReference==1的对象将会被释放掉,因为没有被引用。
若连续两次autorelease会怎样?

cocos2dx 2.x.x内存管理我也只了解这么多,欢迎留言探讨。


原创BLOG : _鞋男 http://blog.csdn.net/wushao126/article/details/41050605


cocos2dx 3.x内存管理机制与2.x差不多,数据结构改变了,用vector<>代替了CCArray,在addObject是无需retain再release,实现方便了不少

void DisplayLinkDirector::mainLoop()
{
    if (_purgeDirectorInNextLoop)
    {
        _purgeDirectorInNextLoop = false;
        purgeDirector();
    }
    else if (! _invalid)
    {
        drawScene();
     
        // release the objects
        PoolManager::getInstance()->getCurrentPool()->clear();
    }
}
void AutoreleasePool::clear()
{
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
    _isClearing = true;
#endif
    for (const auto &obj : _managedObjectArray)
    {
        obj->release();
    }
    _managedObjectArray.clear();
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
    _isClearing = false;
#endif
}

void Ref::release()
{
    CCASSERT(_referenceCount > 0,"reference count should greater than 0");
    --_referenceCount;

    if (_referenceCount == 0)
    {
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
        auto poolManager = PoolManager::getInstance();
        if (!poolManager->getCurrentPool()->isClearing() && poolManager->isObjectInPools(this))
        {
            CCASSERT(false,"The reference shouldn't be 0 because it is still in autorelease pool.");
        }
#endif

#if CC_USE_MEM_LEAK_DETECTION
        untrackRef(this);
#endif
        delete this;
    }
}
上面三段代码是每帧PoolManager管理内存池的代码,对照着2.x的也不难理解。

Ref* Ref::autorelease()
{
    PoolManager::getInstance()->getCurrentPool()->addObject(this);
    return this;
}
void AutoreleasePool::addObject(Ref* object)
{
    _managedObjectArray.push_back(object);
}
由于用的是STL,所以在这里没有个调用retain(),看起来清爽多了 ,简简单单

相关文章

    本文实践自 RayWenderlich、Ali Hafizji 的文章《...
Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@1...
第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从C...
    Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发...
1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《...
   Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试...