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

Cocos2d内存管理分析

2014-10-21 22:23 375 查看



Cocos2d内存管理分析
1、 UML图





2、 说明

步骤1:cocos2d在初始化的时候调用CCDirector中的init方法,在init方法中:

       // create autorelease pool

       CCPoolManager::sharedPoolManager()->push();

           即创建了一个内存自动回收池管理器,并调用push方法

          

步骤2:

void CCPoolManager::push()

{

    CCAutoreleasePool* pPool =new CCAutoreleasePool();       //ref = 1

    m_pCurReleasePool = pPool;

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

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

}

在push方法中主要创建了一个内存自动回收池,并把其设为当前的内存自动回收池,加入到内存自动回收池管理器中,并release该内存自动回收池,但由于addObject会把该内存回收池的引用加1,所以在这儿并不会真正的释放该对象。而该对象会在CCPoolManager::pop()方法和CCPoolManager的析构函数中被释放。

 

   下面就以CCSprite为例,看Cocosdx是怎么管理精灵的内存的。

         步骤5:

                   CCSpirte::create()方法,该方法也是cocos2dx中最常用的工厂方法,这样创建的对象是不需要用户去管理内存的,但这样会增加额外的内存开销,并影响效率。所以如果有需要,可以自己管理内存。

         CCSprite*CCSprite::create()

{

    CCSprite *pSprite = newCCSprite();

    if (pSprite &&pSprite->init())

    {

        pSprite->autorelease();

        return pSprite;

    }

    CC_SAFE_DELETE(pSprite);

    return NULL;

}

CCSprite::create方法中主要是new一个对象,并调用init()初始化,并调用autorelease(),把该对象加入到自动内存回收池中。下面看看CCObject::autorelease的实现。

         CCObject*CCObject::autorelease(void)

{

   CCPoolManager::sharedPoolManager()->addObject(this);

    return this;

}

只是转调了一把。CCPoolManager::addObject实现如下:

void CCPoolManager::addObject(CCObject* pObject)

{

   getCurReleasePool()->addObject(pObject);

}

getCurReleasePool即获取步骤2中创建的CCAutoreleasePool对象,并调用addObject方法

void CCAutoreleasePool::addObject(CCObject* pObject)

{

   m_pManagedObjectArray->addObject(pObject);

 

   CCAssert(pObject->m_uReference > 1, "reference count shouldbe greater than 1");

   ++(pObject->m_uAutoReleaseCount);

    pObject->release(); //no ref count, in this case autorelease pool added.

}

pManagedObjectArray是一个CCArray对象,通过该方法中的addObject把对象加入到内存自动回收池中,并让该对象的引用计数加1。并让该对象的自动引用计数加1,方便后续对该对象的管理。对对象引用计数的操作是在ccCArray:: ccArrayAppendObject中实现的。CCAutoreleasePool::addObject中先是让该对象的引用计数加1,后又调用release方法,让该对象的引用计数减一,所以,CCSprite对象的引用计数还是为1,如果现在不对CCSprite对象做其他的操作,那么,该对象在下一帧的时候就会被自动回收。为什么呢,我们看看CCDisplayLinkDirector::mainLoop(void)方法,即游戏主循环。

         voidCCDisplayLinkDirector::mainLoop(void)

{

    if(m_bPurgeDirecotorInNextLoop)

    {

       m_bPurgeDirecotorInNextLoop = false;

        purgeDirector();

    }

    else if (! m_bInvalid)

     {

         drawScene();

    

         // release theobjects

        CCPoolManager::sharedPoolManager()->pop();       

     }

}       

第一个条件语句会在该游戏结束的时候才会满足该条件,主要是去回收资源。

         第二个条件只有在调用stopAnimation后才不会满足,所以:

         drawScene主要是去绘制当前场景,而pop就是对内存的回收。

         voidCCPoolManager::pop()

{

    if (! m_pCurReleasePool)

    {

        return;

    }

 

    int nCount =m_pReleasePoolStack->count();

 

   m_pCurReleasePool->clear();

 

      if(nCount > 1)

      {

       m_pRel
ae71
easePoolStack->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;*/

}

其对内存的回收是通过clear方法去实现的

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 ();

    }

}

CCARRAY_FOREACH_REVERSE是一个for循环的宏定义,在这个for循环中会把当前内存回收池中所有的对象的uAutoReleaseCount减一,而真正去release这些对象是在removeAllObjects中去实现的,pManagedObjectArray是一个CCArray对象,所以调用的是CCArray:: removeAllObjects方法,该方法会调用ccCArray中的

void ccArrayRemoveAllObjects(ccArray *arr)

 {

        while( arr->num > 0 )

     {

                 (arr->arr[--arr->num])->release();

     }

 }

         该方法会遍历该对象中所有的节点,并调用每个节点的 release方法,下面我们再看看release方法的实现,该方法是在CCObject中

void CCObject::release(void)

{

    CCAssert(m_uReference >0, "reference count should greater than 0");

    --m_uReference;

 

    if (m_uReference == 0)

    {

        delete this;

    }

}

release方法会把该对象的引用计数减一,然后判断该对象的引用计数是否为0,如果该对象的引用计数为0,就删除该对象,这也是智能指针常用的做法。

所以刚刚我们用工厂方法创建的CCSprite对象,如果不对该对象进行其他操作,那么在游戏的下一次循环就会被自动回收。

因此我们在创建一个CCSprite对象后,都会把该对象加入到Layer中去,以防止该对象被自动回收,CCSprite::addChild会调用到CCNode::addChild,然后调用CCNode::insertChild,该方法中会通过ccCArray::ccArrayAppendObjectWithResize方法,把要添加的对象的引用计数加一。

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