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

cocos2dx对象内存管理机制分析

2014-08-06 17:14 375 查看
cocos2dx是通过引用计数的方式管理内存的。这里涉及到4个类:CCObject,CCAutoreleasePool,CCPoolManager和CCDirector;下面介绍这4个类的情况;CCObject是cocos2dx对象的基类(这里指继承于CCObject),里面有一个m_uReference引用计数,它提供了3个主要的方法,如下:
void CCObject::release(void)
{
    CCAssert(m_uReference > 0, "reference count should greater than 0");
    --m_uReference;//计数会减1

    if (m_uReference == 0)
    {
        delete this;
    }
}

void CCObject::retain(void)
{
    CCAssert(m_uReference > 0, "reference count should greater than 0");

    ++m_uReference;
}

CCObject* CCObject::autorelease(void)
{
    CCPoolManager::sharedPoolManager()->addObject(this);
    return this;
}
CCAutoreleasePool是自动对象池,新创建的对象会放到这里面管理,它提供了2个主要方法,如下:
4000
ps: 代码中的m_pManagedObjectArray是CCArray类型的对象,用来存储CCObject对象。
void CCAutoreleasePool::addObject(CCObject* pObject)
{
    m_pManagedObjectArray->addObject(pObject);  //CCArray::addObject()方法会使对象计数+1,具体可进去看源码

    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.计数-1
}
void CCAutoreleasePool::clear(){    if(m_pManagedObjectArray->count() > 0)    {        //CCAutoreleasePool* pReleasePool;#ifdef _DEBUG        int nIndex = m_pManagedObjectArray->count() - 1;#endif        CCObject* pObj = NULL;        CCARRAY_FOREACH_REVERSE(m_pManagedObjectArray, pObj)        {            if(!pObj)                break;            --(pObj->m_uAutoReleaseCount);            //(*it)->release();            //delete (*it);#ifdef _DEBUG            nIndex--;#endif        }        m_pManagedObjectArray->removeAllObjects();//removeAllObjects()方法里面会遍历里面的元素,并且调用release()的,这就意味着对象的引用计数-1;    }}
CCPoolManager是自动释放池的管理类,是一个singleton,主要内容如下:
    CCArray*    m_pReleasePoolStack;     //用来装CCAutoreleasePool*对象,可能不止一个对象池哦    CCAutoreleasePool*                    m_pCurReleasePool;//当前使用的对象池
void CCPoolManager::addObject(CCObject* pObject){    getCurReleasePool()->addObject(pObject); //getCurReleasePool()是取到当前使用的对象池;}
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;*/}
在看看CCDirector,相关代码如下:
void CCDisplayLinkDirector::mainLoop(void){    if (m_bPurgeDirecotorInNextLoop)    {        m_bPurgeDirecotorInNextLoop = false;        purgeDirector();    }    else if (! m_bInvalid)     {         drawScene();              // release the objects         CCPoolManager::sharedPoolManager()->pop();      }}
可以看出在 drawScene();之后会去调用CCPoolManager::pop();就是回收对象是在帧的结尾的下面是一个例子,假如MyClass继承CCObject:MyClass*MyClass::create(){MyClass*pRet= newMyClass();pRet->autorelease();returnpRet;}当某处需要创建一个MyClass类型的对象,如下:MyClass*pMyClass =MyClass::create();pMyClass->retain();........那么整个过程是什么样子的呢,往下看当MyClass::create();被调用后,先newMyClass();,此时引用计数为1(看下面代码);
CCObject::CCObject(void): m_nLuaID(0), m_uReference(1) // when the object is created, the reference count of it is 1, m_uAutoReleaseCount(0)
{......},
然后pRet->autorelease();autorelease()就往对象池中加入一个对象:
CCPoolManager::sharedPoolManager()->addObject(this); //实际上这里的引用计数有一个+1再-1的过程,最终计数不变
此时该对象引用计数还是为1;接着pMyClass->retain();后,计数+1变为2,在这帧结束前在CCDirector中调用了
CCPoolManager::sharedPoolManager()->pop();  //这个方法会调用到CCAutoreleasePool::clear(),而clear方法中会遍历对象池中的元素并且都调用CCObject::release()方法,此时该对象的计数-1变为1了,这就是pMyClass->retain()的引用结果(当然如果还在其他地方也retain()的话,计数就不止1了,反正retain()过n次,计数就为n.)当pMyClass不用了,会调用release()方法,此时计数在-1变为0,被delete掉,ok,这个对象生命结束。
但是可能会问,为什么需要autorelease()呢,那放过来看看,如果不用这种机制,当一个对象new后立马被delete了,那么就没法使用这个对象了。使用autorelease()从对象的new开始到帧结束前的release()之间,提供了一个让第三方引用的时机。

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: