【深刻Cocos2d-x】探索Cocos2d-x中的內存管理-引用計數和自動釋放池

#深刻Cocos2d-x-探索Cocos2d-x中的內存管理-引用計數和自動釋放池html

###引用計數(Reference Count)ios

引用計數是一種在C++中至關古老的內存管理方法,ios中將這種機制包括在NSAutoreleasePool中。全部咱們在Cocos2d-x中也有個類似的東西,叫CCAutoreleasePool,用處基本上同樣,詳細請看:NSAutoreleasePool Class Referencejson

###CCAutoRealeasePoolapi

CCAutoRealeasePool與NSAutoreleasePool有着相同的概念和架構,但有兩個重要區別:網絡

  1. CCAutoreleasePool不能嵌套,因此每一個cocoss2d-x的遊戲實例中僅能有一個,開發者不能建立新的CCAutoreleasePool,而只是注意CCOject的釋放和增長引用計數(realease/retain)就能夠了
  2. CCAutoreleasePool不能在多線程中使用 。因此若是你的遊戲須要一個網絡線程,請僅僅接收數據或者改變網絡中的狀態值,不要調用其中的Cocos2d接口。

CCAutoreleasePool的邏輯是這樣的:當你調用object->autorealease()這個方法時,這個object就被放在了CCAutoreleasePool中,這個計數池能幫你拿着這個object,想一個管家同樣的保存到當前message loop的結尾。等到了當前message loop的結尾若是這個object沒有被任何一個class或者container持有(retain)的話,它就被自動釋放出來。例如:layer->addChild(sprite),這個sprite被加到layer的children list中去,那麼它的生命週期就一直保持到這個layer被釋放的時候,而不是當前message loop的結尾就被釋放。多線程

因此啦,你就不能在網絡線程中管理CCObject啦:在每一個UI線程結束時,autorealease object就會被刪除掉,當你調用這些已經被刪除掉的對象的指針的話,game就會崩掉架構

###CCObject::release(), retain() and autorelease()app

總而言之,有兩種狀況你須要調用 ->realease()方法函數

  1. 當你經過new的方式建立一個CCObject時
  2. 當你獲得一個CCObject的指針,而後在代碼裏調用「retain」方法

下面是一個例子,他不須要realease()oop

CCSprite* sprite = CCSprite::create("player.png");

若是你看了源碼的話,你會發如今create方法裏CCSprite已經調用了autorealease

###使用靜態構造方法

CCSprite::create("player.png") 就是用了靜態構造方法. 在Cocos2d-x中的全部類, 除了單件, 都提供了這種create方法,在其中包含了四個操做:

  1. new an object
  2. call object->init(...)
  3. if init success, e.g. find the texture file successfully, it will call object->autorelease();
  4. return the object marked as autorelease.

全部的 CCAsdf::createWithXxxx(...) 類型的函數都™一個行爲

在使用create方法時,你不用考慮new,delete,autorealease之類的事,只要專一於這一對:object->retain() 和 object->release()

###一個錯誤的實例

一個開發者弄CCArray時弄崩了

<!-- lang: cpp -->
bool HelloWorld::init()
{
    bool bRet = false;
    do
    {
        //////////////////////////////////////////////////////////////////////////
        // super init first
        //////////////////////////////////////////////////////////////////////////

        CC_BREAK_IF(! CCLayer::init());

        //////////////////////////////////////////////////////////////////////////
        // add your codes below...
        //////////////////////////////////////////////////////////////////////////

        CCSprite* bomb1 = CCSprite::create("CloseNormal.png");
        CCSprite* bomb2 = CCSprite::create("CloseNormal.png");
        CCSprite* bomb3 = CCSprite::create("CloseNormal.png");
        CCSprite* bomb4 = CCSprite::create("CloseNormal.png");
        CCSprite* bomb5 = CCSprite::create("CloseNormal.png");
        CCSprite* bomb6 = CCSprite::create("CloseNormal.png");

        addChild(bomb1,1);
        addChild(bomb2,1);
        addChild(bomb3,1);
        addChild(bomb4,1);
        addChild(bomb5,1);
        addChild(bomb6,1);

        m_pBombsDisplayed = CCArray::create(bomb1,bomb2,bomb3,bomb4,bomb5,bomb6,NULL);
        //m_pBombsDisplayed is defined in the header as a protected var.
        // <--- We should add m_pBombsDisplayed->retain() here to avoid crashing in HelloWorld::refreshData()

        this->scheduleUpdate();

        bRet = true;
    } while (0);

    return bRet;
}

void HelloWorld::update(ccTime dt)
{
    refreshData();
}

void HelloWorld::refreshData()
{
    m_pBombsDisplayed->objectAtIndex(0)->setPosition(cpp(100,100));
}

這哥們犯了什麼錯誤呢?m_pBombsDisplayed是由create方法建立的,他被標記爲autorealease,

因此在message loop結束時CCArray就被刪除了

當隨後的message loop調用 HelloWorld::update(ccTime)時,m_pBombsDisplayed已是null了,因此解決辦法是在create方法後加上retain,在析構方法中加realease

翻譯原文請點擊這裏

相關文章
相關標籤/搜索