程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> cocos2d-x回收池原理,cocos2d-x回收

cocos2d-x回收池原理,cocos2d-x回收

編輯:C++入門知識

cocos2d-x回收池原理,cocos2d-x回收


 

cocos2d-x源於cocos2d-iphone,為了與Objective-c一致,cocos2d-x也采用了引用計數與自動回收的內存管理機制。

要現實自動內存回收,需繼承於cocos2d-x的根類CCObject。當然自動釋放會影響性能的。

 

cocos2d-x中有很多靜態工場方法,例如以create開頭的,這些靜態工場方法創建的對象都使用的autorelease,試想如果不用autorelease,

CCObject* create(){CCObject *ret = new CCObject(); return ret;}

此時函數內的引用在函數結束時就結束了,但是對方沒有被釋放,如果返回的ret沒有被用戶引用或者釋放,那麼就造成了內存洩露。所以加入autorelease是個不錯的解決方法。

 

看看CCObject的這兩個字段和方法:

復制代碼
protected:
    // 引用計數
    unsigned int        m_uReference;
    // 自動釋放次數   以前是bool m_bManaged;標識是否采用自動釋放
    unsigned int        m_uAutoReleaseCount;
public:
    void release(void);
    void retain(void);
    CCObject* autorelease(void);
    unsigned int retainCount(void);
復制代碼

有這麼一個原則:誰引用誰retain和release,對象傳值時先retain再release(避免自己給自己傳值時,先release可能會釋放對象),調用release方法,當引用計數為0時,就會delete此對象。

內存管理autorelease是怎麼實現的呢,進入autorelease看到調用了下面這個函數:

CCPoolManager::sharedPoolManager()->addObject(this);將對象加入回收池

復制代碼
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.
}
復制代碼

函數中將對象加入管理數組中,再對自動釋放計數+1,然後release使引用計數-1。

當create一個對象時,new使引用計數為1,調用autorelease後,加入回收池,然後release引用計數-1。那麼此時引用計數為0嗎?

答案肯定不是,如果為0,此時該對象就會被delete。cocos2d-x中的數據結構轉為這種內存管理設置,如CCArray,當對array調用addObject時,就會調用retain使引用計數加1,當array調用removeObject時就會release。那麼當加入回收池後,此時的這個引用歸回收池所有,當一幀結束釋放回收池的時候,回收池中的所有對象都會調用release。如果此時沒有其他對象引用該對象,則該對象會被刪除。

 

來看看主循環mainLoop中的調用:

復制代碼
    if (m_bPurgeDirecotorInNextLoop)
    {
        m_bPurgeDirecotorInNextLoop = false;
        purgeDirector();
    }
    else if (! m_bInvalid)
     {
         drawScene();
     
         // release the objects
         CCPoolManager::sharedPoolManager()->pop();        
     }
復制代碼

每一幀結束調用sharedPoolManager()->pop()此時棧頂的回收池就被釋放,

復制代碼
void CCPoolManager::pop()
{
    if (! m_pCurReleasePool)
    {
        return;
    }

     int nCount = m_pReleasePoolStack->count();

    m_pCurReleasePool->clear();
 
      if(nCount > 1)
      {
        //釋放棧頂的回收池
        m_pReleasePoolStack->removeObjectAtIndex(nCount-1);
        m_pCurReleasePool = (CCAutoreleasePool*)m_pReleasePoolStack->objectAtIndex(nCount - 2);
    }
}
復制代碼

此時池中的所有對象都會被release,如果沒有其它的對象(場景、層、數組等)在引用他們,這些對象就會被delete。

而新一幀開始後,第一個調用autorelease的對象在內部調用getCurReleasePool()時,如果棧中沒有回收池,就會push一個回收池,sharedPoolManager()->push()。

復制代碼
CCAutoreleasePool* CCPoolManager::getCurReleasePool()
{
    if(!m_pCurReleasePool)
    {
        push();
    }
    CCAssert(m_pCurReleasePool, "current auto release pool should not be null");
    return m_pCurReleasePool;
}
復制代碼

 

 

 

可以看出每一幀回收池都要建立、刪除,而且添加對象進入回收池,那麼性能方面當然會受到影響,當回收池中對象很多時,表現得很明顯。

那麼解決方法1:性能要求高的情況下不要輕易使用自動回收池。

 

方法2:手動釋放並創建一個回收池

CCPoolManager::shardPoolManager()->push();
for(int i=0; i!=n; ++i)
{
     objArray[i]->autorelease();
}
CCPoolManager::shardPoolManager()->pop();

這樣就不會讓自動釋放的對象集中在一幀結束的時候。

 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved