国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Android - Cocos2d-x的內(nèi)存管理總結(jié)

Cocos2d-x的內(nèi)存管理總結(jié)

2021-03-01 16:11Android開發(fā)網(wǎng) Android

這篇文章主要介紹了Cocos2d-x的內(nèi)存管理總結(jié),詳解探討了手工對象內(nèi)存管理、自動對象內(nèi)存管理、自動釋放的時機(jī)等問題,需要的朋友可以參考下

Cocos2d-x引擎的核心是用C++編寫的,那對于所有使用該引擎的游戲開發(fā)人員來說,內(nèi)存管理是一道繞不過去的坎。

關(guān)于Cocos2d-x內(nèi)存管理,網(wǎng)上已經(jīng)有了許多參考資料,有些資料寫的頗為詳實,因為在內(nèi)存管理這塊我不想多費筆墨,只是更多的將思路描述清楚。

一、對象內(nèi)存引用計數(shù)

Cocos2d-x內(nèi)存管理的基本原理就是對象內(nèi)存引用計數(shù),Cocos2d-x將內(nèi)存引用計數(shù)的實現(xiàn)放在了頂層父類CCObject中,這里將涉及引用計數(shù)的CCObject的成員和方法摘錄出來:

復(fù)制代碼 代碼如下:


class CC_DLL CCObject : public CCCopying
{
public:
   … …
protected:
    // count of references
    unsigned int        m_uReference;
    // count of autorelease
    unsigned int        m_uAutoReleaseCount;
public:
    void release(void);
    void retain(void);
    CCObject* autorelease(void);
    … ….
}

 

CCObject::CCObject(void)
: m_nLuaID(0)
, m_uReference(1) // when the object is created, the reference count of it is 1
, m_uAutoReleaseCount(0)
{
  … …
}

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

    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;
}


先不考慮autorelease與m_uAutoReleaseCount(后續(xù)細(xì)說)。計數(shù)的核心字段是m_uReference,可以看到:

 

* 當(dāng)一個Object初始化(被new出來時),m_uReference = 1;
* 當(dāng)調(diào)用該Object的retain方法時,m_uReference++;
* 當(dāng)調(diào)用該Object的release方法時,m_uReference–,若m_uReference減后為0,則delete該Object。

二、手工對象內(nèi)存管理

在上述對象內(nèi)存引用計數(shù)的原理下,我們得出以下Cocos2d-x下手工對象內(nèi)存管理的基本模式:

復(fù)制代碼 代碼如下:


CCObject *obj = new CCObject();
obj->init();
…. …
obj->release();

 

在Cocos2d-x中CCDirector就是一個手工內(nèi)存管理的典型:

CCDirector* CCDirector::sharedDirector(void)
{
    if (!s_SharedDirector)
    {
        s_SharedDirector = new CCDisplayLinkDirector();
        s_SharedDirector->init();
    }

    return s_SharedDirector;
}

void CCDirector::purgeDirector()
{
    … …
    // delete CCDirector
    release();
}

 

三、自動對象內(nèi)存管理

所謂的“自動對象內(nèi)存管理”,指的就是哪些不再需要的object將由Cocos2d-x引擎替你釋放掉,而無需你手工再調(diào)用Release方法。

自動對象內(nèi)存管理顯然也要遵循內(nèi)存引用計數(shù)規(guī)則,只有當(dāng)object的計數(shù)變?yōu)?時,才會釋放掉對象的內(nèi)存。

自動對象內(nèi)存管理的典型模式如下:

復(fù)制代碼 代碼如下:

CCYourClass *CCYourClass::create()
{
    CCYourClass*pRet = new CCYourClass();
    if (pRet && pRet->init())
    {
        pRet->autorelease();
        return pRet;
    }
    else
    {
        CC_SAFE_DELETE(pRet);
        return NULL;
    }
}

 

一般我們通過一個單例模式創(chuàng)建對象,與手工模式不同的地方在于init后多了一個autorelease調(diào)用。這里再把a(bǔ)utorelease調(diào)用的實現(xiàn)摘錄一遍:

復(fù)制代碼 代碼如下:

CCObject* CCObject::autorelease(void)
{
    CCPoolManager::sharedPoolManager()->addObject(this);
    return this;
}

 

追溯addObject方法:

復(fù)制代碼 代碼如下:


// cocoa/CCAutoreleasePool.cpp

 

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

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.
}

// cocoa/CCArray.cpp
void CCArray::addObject(CCObject* object)                                                                                                  
{                                                                                                                                         
    ccArrayAppendObjectWithResize(data, object);                            

// support/data_support/ccCArray.cpp
void ccArrayAppendObjectWithResize(ccArray *arr, CCObject* object)                                                                         
{                                                                                                                  
    ccArrayEnsureExtraCapacity(arr, 1);                                                             
    ccArrayAppendObject(arr, object);                                        
}

void ccArrayAppendObject(ccArray *arr, CCObject* object)
{
    CCAssert(object != NULL, "Invalid parameter!");
    object->retain();
    arr->arr[arr->num] = object;
    arr->num++;
}

 

調(diào)用層次挺深,涉及的類也眾多,這里歸納總結(jié)一下。

Cocos2d-x的自動對象內(nèi)存管理基于對象引用計數(shù)以及CCAutoreleasePool(自動釋放池)。引用計數(shù)前面已經(jīng)說過了,這里單說自動釋放池。Cocos2d-x關(guān)于自動對象內(nèi)存管理的基本類層次結(jié)構(gòu)如下:

復(fù)制代碼 代碼如下:

    CCPoolManager類 (自動釋放池管理器)
        – CCArray*    m_pReleasePoolStack; (自動釋放池棧,存放CCAutoreleasePool類實例)

    CCAutoreleasePool類
        – CCArray*    m_pManagedObjectArray; (受管對象數(shù)組)


CCObject關(guān)于內(nèi)存計數(shù)以及自動管理有兩個字段:m_uReference和m_uAutoReleaseCount。前面在手工管理模式下,我只提及了m_uReference,是m_uAutoReleaseCount該亮相的時候了。我們沿著自動釋放對象的創(chuàng)建步驟來看看不同階段,這兩個重要字段的值都是啥,代表的是啥含義:

復(fù)制代碼 代碼如下:

CCYourClass*pRet = new CCYourClass();    m_uReference = 1; m_uAutoReleaseCount = 0;
pRet->init();                           m_uReference = 1; m_uAutoReleaseCount = 0;
pRet->autorelease();                   
    m_pManagedObjectArray->addObject(pObject); m_uReference = 2; m_uAutoReleaseCount = 0;
    ++(pObject->m_uAutoReleaseCount);          m_uReference = 2; m_uAutoReleaseCount = 1;
    pObject->release();                        m_uReference = 1; m_uAutoReleaseCount = 1;


在調(diào)用autorelease之前,兩個值與手工模式并無差別,在autorelease后,m_uReference值沒有變,但m_uAutoReleaseCount被加1。

 

m_uAutoReleaseCount這個字段的名字很容易讓人誤解,以為是個計數(shù)器,但實際上絕大多數(shù)時刻它是一個標(biāo)識的角色,以前版本代碼中有一個布爾字段m_bManaged,似乎后來被m_uAutoReleaseCount替換掉了,因此m_uAutoReleaseCount兼有m_bManaged的含義, 也就是說該object是否在自動釋放池的控制之下,如果在自動釋放池的控制下,自動釋放池會定期調(diào)用該object的release方法,直到該 object內(nèi)存計數(shù)降為0,被真正釋放。否則該object不能被自動釋放池自動釋放內(nèi)寸,需手工release。這個理解非常重要,再后面我們能用到這個理解。


四、自動釋放時機(jī)

通過autorelease我們已經(jīng)將object放入autoreleasePool中,那究竟何時對象會被釋放呢?答案是每幀執(zhí)行一次自動內(nèi)存對象釋放操作。

在“Hello,Cocos2d-x”一文中,我們講過整個Cocos2d-x引擎的驅(qū)動機(jī)制在于GLThread的guardedRun函數(shù),后者會 “死循環(huán)”式(實際幀繪制頻率受到屏幕vertsym信號的影響)的調(diào)用Render的onDrawFrame方法實現(xiàn),而最終程序會進(jìn)入 CCDirector::mainLoop方法中,也就是說mainLoop的執(zhí)行頻率是每幀一次。我們再來看看mainLoop的實現(xiàn):

 

復(fù)制代碼 代碼如下:


void CCDisplayLinkDirector::mainLoop(void)
{
    if (m_bPurgeDirecotorInNextLoop)
    {
        m_bPurgeDirecotorInNextLoop = false;
        purgeDirector();
    }
    else if (! m_bInvalid)
     {
         drawScene();

 

         // release the objects
         CCPoolManager::sharedPoolManager()->pop();
     }
}

 

這次我們要關(guān)注的不是drawScene,而是 CCPoolManager::sharedPoolManager()->pop(),顯然在游戲未退出 (m_bPurgeDirecotorInNextLoop決定)的條件下,CCPoolManager的pop方法每幀執(zhí)行一次,這就是自動釋放池執(zhí)行的起點。

復(fù)制代碼 代碼如下:


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

 

真正釋放對象的方法是m_pCurReleasePool->clear()。

復(fù)制代碼 代碼如下:


void CCAutoreleasePool::clear()
{
    if(m_pManagedObjectArray->count() > 0)
    {
        CCObject* pObj = NULL;
        CCARRAY_FOREACH_REVERSE(m_pManagedObjectArray, pObj)
        {
            if(!pObj)
                break;

 

            –(pObj->m_uAutoReleaseCount);
        }

        m_pManagedObjectArray->removeAllObjects();
    }
}

void CCArray::removeAllObjects()    
{  
    ccArrayRemoveAllObjects(data);                   
}

void ccArrayRemoveAllObjects(ccArray *arr)                   
{                      
    while( arr->num > 0 )                     
    {                   
        (arr->arr[--arr->num])->release();              
    }                   
}

 

不出預(yù)料,當(dāng)前自動釋放池遍歷每個“受控制”Object,–m_uAutoReleaseCount,并調(diào)用該object的release方法。

我們接著按釋放流程來看看m_uAutoReleaseCount和m_uReference值的變化:

復(fù)制代碼 代碼如下:

CCPoolManager::sharedPoolManager()->pop();  m_uReference = 0; m_uAutoReleaseCount = 0;

 

五、自動釋放池的初始化

自動釋放池本身是何時出現(xiàn)的呢?回顧一下Cocos2d-x引擎的初始化過程(android版),引擎初始化實在Render的onSurfaceCreated方法中進(jìn)行的,我們不難追蹤到以下代碼:

復(fù)制代碼 代碼如下:


//hellocpp/jni/hellocpp/main.cpp
Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit {

    //這里CCDirector第一次被創(chuàng)建
    if (!CCDirector::sharedDirector()->getOpenGLView())
    {
        CCEGLView *view = CCEGLView::sharedOpenGLView();
        view->setFrameSize(w, h);

 

        AppDelegate *pAppDelegate = new AppDelegate();
        CCApplication::sharedApplication()->run();
    }
}

CCDirector* CCDirector::sharedDirector(void)
{
    if (!s_SharedDirector)
    {
        s_SharedDirector = new CCDisplayLinkDirector();
        s_SharedDirector->init(); 
    }

    return s_SharedDirector;
}

bool CCDirector::init(void)
{
    setDefaultValues();

    … …

    // create autorelease pool
    CCPoolManager::sharedPoolManager()->push();

    return true;
}

 

六、探尋Cocos2d-x內(nèi)核對象的自動化內(nèi)存釋放

前面我們基本了解了Cocos2D-x的自動化內(nèi)存釋放原理。如果你之前翻看過一些Cocos2d-x的內(nèi)核源碼,你會發(fā)現(xiàn)很多內(nèi)核對象都是通過單例模式create出來的,也就是說都使用了autorelease將自己放入自動化內(nèi)存釋放池中被管理。

比如我們在HelloCpp中看到過這樣的代碼:

復(fù)制代碼 代碼如下:


//HelloWorldScene.cpp
bool HelloWorld::init() {
     …. ….
    // add "HelloWorld" splash screen"
    CCSprite* pSprite = CCSprite::create("HelloWorld.png");

 

    // position the sprite on the center of the screen
    pSprite->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));

    // add the sprite as a child to this layer
    this->addChild(pSprite, 0);
    … …
}

 

CCSprite采用自動化內(nèi)存管理模式create object(cocos2dx/sprite_nodes/CCSprite.cpp),之后將自己加入到HelloWorld這個CCLayer實例 中。按照上面的分析,create結(jié)束后,CCSprite object的m_uReference = 1; m_uAutoReleaseCount = 1。一旦如此,那么在下一幀時,該object就會被CCPoolManager釋放掉。但我們在屏幕上依舊可以看到該Sprite的存在,這是怎么回事呢?

問題的關(guān)鍵就在this->addChild(pSprite, 0)這行代碼中。addChild方法實現(xiàn)在CCLayer的父類CCNode中:

復(fù)制代碼 代碼如下:


//  cocos2dx/base_nodes/CCNode.cpp
void CCNode::addChild(CCNode *child, int zOrder, int tag)
{
    … …
    if( ! m_pChildren )
    {
        this->childrenAlloc();
    }

 

    this->insertChild(child, zOrder);

    … …
}

void CCNode::insertChild(CCNode* child, int z)
{
    m_bReorderChildDirty = true;
    ccArrayAppendObjectWithResize(m_pChildren->data, child);
    child->_setZOrder(z);
}

void ccArrayAppendObjectWithResize(ccArray *arr, CCObject* object)
{
    ccArrayEnsureExtraCapacity(arr, 1);
    ccArrayAppendObject(arr, object);
}

void ccArrayAppendObject(ccArray *arr, CCObject* object)
{
    CCAssert(object != NULL, "Invalid parameter!");
    object->retain();
    arr->arr[arr->num] = object;
    arr->num++;
}

 

又是一系列方法調(diào)用,最終我們來到了ccArrayAppendObject方法中,看到了陌生而又眼熟的retain方法調(diào)用。

在本文開始我們介紹CCObject時,我們知道retain是CCObject的一個方法,用于增加m_uReference計數(shù)。而實際上retain還隱含著“保留”這層意思。

在完成this->addChild(pSprite, 0)調(diào)用后,CSprite object的m_uReference = 2; m_uAutoReleaseCount = 1,這很關(guān)鍵。

我們在腦子里再過一下自動釋放池釋放object的過程:–m_uReference, –m_uAutoReleaseCount。一幀之后,兩個值變成了m_uReference = 1; m_uAutoReleaseCount = 0。還記得前面說過的m_uAutoReleaseCount的另外一個非計數(shù)含義么,那就是表示該object是否“受控”,現(xiàn)在值為0,顯然不再受自動釋放池的控制了,后續(xù)即便再執(zhí)行100次內(nèi)存自動釋放,也不會影響到該object的存活。

后續(xù)要想釋放這個“精靈”,我們還是需要手工調(diào)用release,或再調(diào)用其autorelease方法。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 亚洲综合色成在线播放 | 精品国产乱码久久久久久影片 | 久久精品日| 色猫猫国产区一区二在线视频 | 九九热在线视频观看这里只有精品 | 91精品国产乱码久久久久久 | 亚洲欧美日韩在线 | 一级免费片 | 欧美综合成人网 | 国产精品久久久久久久久久新婚 | 国产黄色免费网站 | 欧美精品1区2区 | 中文一区 | 亚洲免费视频在线 | 久久99精品视频 | 人人天天色 | 精品久久久久国产 | 日本久久久 | 日本99精品 | 免费在线一区二区 | 亚洲精品成人天堂一二三 | 欧美区国产 | 丝瓜视频在线观看 | 精品国产一区二区三区忘忧草 | 午夜免费小视频 | 大毛片 | 丝瓜视频在线观看 | 日韩高清一区二区 | 欧美午夜寂寞影院 | 成人高清视频在线观看 | 日韩精品一区二区在线观看 | 日韩免费在线 | 一二三区视频 | 久久国产一区二区 | 亚洲一区在线免费观看 | 久久99蜜桃综合影院免费观看 | 欧美三级视频 | 国产传媒视频 | 在线播放中文字幕 | 91免费版在线观看 | 美女h视频 |