日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Cocos2d-x内存管理研究二

發布時間:2024/6/18 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Cocos2d-x内存管理研究二 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://hi.baidu.com/tzkt623/item/46a26805adf7e938a3332a04

??上一篇我們講了內核是如何將指針加入管理類進行管理.這次我將分析一下內核是如何自動釋放指針的.
??不過在這之前,我們要先引入另一個類.Cocos2d-x的核心類之一CCDirector.這個類可以說是引擎最主要的類了,沒有他,引擎內的所有東西都無法運轉起來.由于這個類有點大,做的事情很多,我就不一一粘出來看了,我們只關心跟內存管理有關的函數.
??因為一部片子只需要一個導演,所以CCDirector也就是一個單例類,是多重繼承自CCObject和TypeInfo,有什么用,暫時不管.不過是采用的二段構建的單例.什么是二段構建,說簡單點,就是不在構造函數中做初始化工作,而在另一個函數里做初始化工作.這樣做有什么好處?可以說沒有好處,也可以說有好處.的看用的人是出于一種什么樣的目的了.比如說我們這里,如果不用二段構建是不可能實現的.因為CCDirector是個抽象類,我們知道,抽象類是不能被實例化的,也就是說,你new?XXX是不可能的,編譯器直接彈錯.所以要想子類擁有父類的初始化功能,那只能另外寫一個了.
那我們是如何構建的CCDirector這個單例的呢?
static?CCDisplayLinkDirector?*s_SharedDirector?=?NULL;
CCDirector*?CCDirector::sharedDirector(void)
{
???if?(!s_SharedDirector)
???{
???????s_SharedDirector?=?new?CCDisplayLinkDirector();
???????s_SharedDirector->init();
???}

???return?s_SharedDirector;
}
看見了吧,他其實是new了一個自己的子類,來完成自己的功能的.而這個子類里,就有我們非常重要的一個函數.
在CCDirector的初始化函數里,我們看到了一個熟悉的面孔
bool?CCDirector::init(void)
{
???CCLOG("cocos2d:?%s",?cocos2dVersion());
???.........................................
???//?create?autorelease?pool
???CCPoolManager::sharedPoolManager()->push();

???return?true;
}
他在整個內核開始運行之前,就初始化了一個內存管理類.之后,在他的析構函數里
CCDirector::~CCDirector(void)
{
???CCLOG("cocos2d:?deallocing?CCDirector?%p",?this);
????.....................
???//?pop?the?autorelease?pool
???CCPoolManager::sharedPoolManager()->pop();
???CCPoolManager::purgePoolManager();
????...........................
}
用管理類執行了一個彈棧操作pop().不過看到這里,我有點不解,pop是彈出當前管理池并clear掉,那如果當前有幾個管理池同時存在呢?只彈一次,后面幾個怎么辦?我們還是慢慢來吧.
purgePoolManager()其實是這樣
void?CCPoolManager::purgePoolManager()
{
???CC_SAFE_DELETE(s_pPoolManager);
}
他刪掉當前單例的指針.這樣整個單例所保存的數據都會被刪除掉,所以也就不用pop所有的元素了.
然后這個CCDirector?中剩下的唯一跟內存有關的,也是最最重要的函數mainLoop(),從他的名字我們就能看出來他的重要性了--主循環.他是一個純虛函數virtual?void?mainLoop(void)?=?0,在上面提到的子類CCDisplayLinkDirector中被覆寫了.
現在我們來看看這個類
class?CCDisplayLinkDirector?:?public?CCDirector
{
public:
???CCDisplayLinkDirector(void)?
???????:?m_bInvalid(false)
???{}

???virtual?void?mainLoop(void);
???virtual?void?setAnimationInterval(double?dValue);
???virtual?void?startAnimation(void);
???virtual?void?stopAnimation();

protected:
???bool?m_bInvalid;
};
他其實就是覆寫了抽象類的幾個純虛函數而已.并且通過注釋,我們知道他還有些其他的功能和限制.
1.他負責顯示并以一定的頻率刷新計時器.
2.計時器和界面繪制都是通過一定的頻率是同步進行的.
3.只支持每秒60,30,15幀設置.
這些不屬于我們討論范圍,簡答提一下,我們只關心重要的mainLoop()
void?CCDisplayLinkDirector::mainLoop(void)
{
???if?(m_bPurgeDirecotorInNextLoop)
???{
???????m_bPurgeDirecotorInNextLoop?=?false;
???????purgeDirector();
???}
???else?if?(!?m_bInvalid)
????{
????????drawScene();
????
????????//?release?the?objects
????????CCPoolManager::sharedPoolManager()->pop();???????
????}
}
這里在沒有失效的狀況下(即m_bInvalid不為真),他會執行管理池中的pop函數.至于何時m_bInvalid為真,其實是在這里
void?CCDisplayLinkDirector::stopAnimation(void)
{
???m_bInvalid?=?true;
}
而上面的條件語句中的這個變量m_bPurgeDirecotorInNextLoop,我們從名字里就能看出來,他是否是結束CCDirector的一個標志.既然是mainLoop,那就一定要Loop起來,而這里并沒有看到任何Loop的跡象.于是我在內核中查找一下mainLoop在哪里被用過.
int?CCApplication::run()
{
???PVRFrameEnableControlWindow(false);

???//?Main?message?loop:
???MSG?msg;
???LARGE_INTEGER?nFreq;
???LARGE_INTEGER?nLast;
???LARGE_INTEGER?nNow;

???QueryPerformanceFrequency(&nFreq);
???QueryPerformanceCounter(&nLast);

???//?Initialize?instance?and?cocos2d.
???if?(!applicationDidFinishLaunching())
???{
???????return?0;
???}
???CCEGLView*?pMainWnd?=?CCEGLView::sharedOpenGLView();
???pMainWnd->centerWindow();
???ShowWindow(pMainWnd->getHWnd(),?SW_SHOW);
???while?(1)
???{
???????if?(!?PeekMessage(&msg,?NULL,?0,?0,?PM_REMOVE))
???????{
???????????//?Get?current?time?tick.
???????????QueryPerformanceCounter(&nNow);
???????????//?If?it's?the?time?to?draw?next?frame,?draw?it,?else?sleep?awhile.
???????????if?(nNow.QuadPart?-?nLast.QuadPart?>m_nAnimationInterval.QuadPart)
???????????{
???????????????nLast.QuadPart?=?nNow.QuadPart;
???????????????CCDirector::sharedDirector()->mainLoop();
???????????}
???????????else
???????????{
???????????????Sleep(0);
???????????}
???????????continue;
???????}
???????if?(WM_QUIT?==?msg.message)
???????{
???????????//?Quit?message?loop.
???????????break;
???????}
???????//?Deal?with?windows?message.
???????if?(!?m_hAccelTable?||?!?TranslateAccelerator(msg.hwnd,m_hAccelTable,?&msg))
???????{
???????????TranslateMessage(&msg);
???????????DispatchMessage(&msg);
???????}
???}
???return?(int)?msg.wParam;
}
如此大的一個while(1),就是在這里循環的.這個run又是在哪里運行的呢?大家看工程里的main.cpp
int?APIENTRY?_tWinMain(HINSTANCE?hInstance,
??????????????????????HINSTANCE?hPrevInstance,
??????????????????????LPTSTR???lpCmdLine,
??????????????????????int??????nCmdShow)
{
???UNREFERENCED_PARAMETER(hPrevInstance);
???UNREFERENCED_PARAMETER(lpCmdLine);

???//?create?the?application?instance
???AppDelegate?app;
???CCEGLView*?eglView?=?CCEGLView::sharedOpenGLView();
???eglView->setFrameSize(960,?640);
???returnCCApplication::sharedApplication()->run();
}
在這里,WIN32平臺下的入口函數中,我們的引擎就已經啟動了.其他的功能,是啟動的一些初始化工作,以及跨平臺的東西,這里不在討論范圍之內,我們只管內存管理的東西.
好,基本的過程我都找到了,現在來理一下自動釋放的思路.
??假設我們程序已經運行,并且已經存進指針了.那么mainLoop這個函數,在不受到阻礙的情況下,會一直執行,并且一直執行CCPoolManager::sharedPoolManager()->pop().這里我們再把這個pop搬出來看看.還有一個附帶的clear().
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);
???}
}
void?CCAutoreleasePool::clear()
{
???if(m_pManagedObjectArray->count()?>?0)
???{
???????//CCAutoreleasePool*?pReleasePool;
???????CCObject*?pObj?=?NULL;
???????CCARRAY_FOREACH_REVERSE(m_pManagedObjectArray,?pObj)
???????{
???????????if(!pObj)
???????????????break;
???????--(pObj->m_uAutoReleaseCount);
????????}
???????m_pManagedObjectArray->removeAllObjects();
???}
}
1.如果沒有有釋放池,就不做任何事,我們有池,一開始就push了一個進去.
2.記錄當前池中的指針個數,假設我們有3個.在棧中的順序以及引用計數分別為4(最后一針),2(第二針),1(第一針);
3.清除掉當前池中的指針.釋放的過程是,遍歷池中每一個指針,將他們的自動釋放計數減一,然后removeAllObject.看看removeAllObjects()干了些什么事吧.
void?CCArray::removeAllObjects()
{
???ccArrayRemoveAllObjects(data);
}
額,他其實只是調用了一下ccArray的函數而已,而里面的參數data,就是ccArray結構體的指針,也就是我們當前的自動釋放池.
/**?Removes?all?objects?from?arr?*/
void?ccArrayRemoveAllObjects(ccArray?*arr)
{
???while(?arr->num?>?0?)
???{
???????(arr->arr[--arr->num])->release();
???}
}
這個函數寫著,從數組里移除所有的指針.其實不算是移除,不算是真正的移除,他只是遍歷了一次儲存指針的內存地址(即儲存內存地址的內存塊),并分別執行了一次release操作,即將我們指針的引用計數減1,如果減一之后為0了,那么就刪除(delete)這個指針.

我來模擬一下他的運行過程:
1.找到第一個引用計數為4的指針(最后一針),將他的釋放計數減1,變為0;然后找到第二針,釋放計數減1,變為0;最后找到第一針,釋放計數減1,變為0.?
2.執行removeAll操作,將棧中每一個指針的引用計數減1.找到最后一針,4->3,第二針2->1,第一針1->0,然后第一針執行delete?this操作.即立刻執行析構函數.
CCObject::~CCObject(void)
{
???//?if?the?object?is?managed,?we?should?remove?it
???//?from?pool?manager
???if?(m_uAutoReleaseCount?>?0)
???{
???????CCPoolManager::sharedPoolManager()->removeObject(this);
???}
???//?if?the?object?is?referenced?by?Lua?engine,?remove?it
????.....................
}
不過因為m_uAutoReleaseCount已經變成0了,就等于什么都不做,只是例行C++內核過程.那前面一篇提到的m_uAutoReleaseCount什么時候會大一1,這個經過我的研究發現,他不能大于1,他只有0和1兩個值,你把它定成bool類型的也可以,只是不方便運算.

呵呵,重點來了.別以為delete干了件跟牛X的事,其實很多初學者都被他的名字騙了.delete其實只干了一件事,那就是把指針指向的內存中的數據給刪了,但是指針并沒有消失.他任然存在.這就是傳說中的野指針,瞎指!,如果使用它,可能就會出現莫名其妙的BUG.所以,一般delete后,都要將指針的賦值為NULL,讓系統知道,這指針暫時沒用了.不過這里是delete?this,this這個指針是極平常又不平常的一個東西,每個類生成的時候,都會自動帶一個this指針.this指向的其實就是這個類自己,那delete?this就等于"自殺".C++中,允許一個類通過成員函數申請"自殺操作",不過你必須保證,這個類是new出來的,不是對象,而且"自殺"是并且必須是這個類執行的最后一個操作,之后不在對這個類做任何有關數據,以及檢查指針等操作.(想對C++有更深的了解,大家可以去看侯捷先生的<<深度探索C++對象模型>>)那你說,我把delete?this放在析構里就行了.NO,這是絕對不行的,delete?this之后的第一個操作就是執行析構函數,如果再放進去,會形成代碼無限循環,導致堆棧溢出.

這樣看來,我們保存指針數組中,任然有3個指針存在,雖然有個已經廢了........
3.mainLoop再運行一次,然后pop在次執行.不過看到這里我出現了疑問,因為前一次的pop操作,僅僅只是釋放了指針所指向的內存,但并沒有把指針賦值為NULL,所以,如果再次操作指針,豈不是變成操作野指針了!來吧,再看看代碼.
通過把輸出數據打印到控制臺,我發現了一個現象.
CCPoolManager::pop?1
CCAutoreleasePool::clear?4
0
1
2
3
..................
CCPoolManager::pop?1
CCAutoreleasePool::clear?0
也就是說,在pop一次之后,當前釋放池中所儲存的指針全部被移除了,不是刪除指針,只是從數組中把它們去除.

注意,以下為我個人分析過程中非常重要的一段!!!

這里我要重要提示一下,這里卡了我很久很久,也廢了我很多的時間!大家還記得那個自動釋放的計數么?就是這玩意m_uAutoReleaseCount,他在add中被加了1,在clear中被減一.開始我的想法是,這個值只要是1,就說明他被加入了自動管理池中管理,為0表示沒有加入自動管理池.但是我發現我錯了,我找遍了整個內核,都沒有找到有哪個地方在判斷這個值是否為1(除了CCObject的析構,不過那里沒有實際意義).

也就是說,按照我推理的思路,在pop中清理一次指針后,你得把指針移除吧,所以我想到了removeXX函數,可是他們一次也沒有被執行.但是,上面的信息中卻顯示了釋放池中沒有元素了.那是怎么釋放的呢?我這時想到了那個釋放計數,他們不是在clear中被歸零了么,應該有個判斷,找到歸零的指針就刪除,可惜我錯了,我愣是沒找到這樣的或類似的方法.那這數組究竟是如何變成0的呢.

其實秘密在這里.還記得上面自動釋放池執行的那個函數么?在clear中的removeAllObjects,他最終執行的函數是ccArrayRemoveAllObjects,而這個函數干的事我們都知道,那就是

???while(?arr->num?>?0?)
???{
???????(arr->arr[--arr->num])->release();
???}

等一下,這里有個非常陰險的地方,不注意看完全看不出來,我就是沒注意,就是這個東西!!!!--arr->num!!!!.最開始我僅僅認為這是循環遍歷數組執行release操作.天哪,當我分析了一遍又一遍時,才發現,這就是讓自動釋放池數組變成0的原因所在!

內核作者并沒有真正的把數組釋放掉,而是強行把數組的元素個數歸零了!!!!!

這句判斷if(m_pManagedObjectArray->count()>?0),其中的count()也就是獲得數組元素個數的函數,他的原型是這樣的.

unsigned?int?CCArray::count()

{

???return?data->num;

}

其中的data就是一個指向ccArray的指針,而ccArray結構體中的第一個參數就是num.

各位肯定還記得我說過的,只delete指針不賦值NULL,是沒辦法真正刪除一個指針的,而他會成為野指針.作者僅僅執行了delete?this,沒有賦值NULL,clear中卻還繼續對野指針進行操作,但是整個引擎卻沒有出現絲毫的BUG.也就是這個原因,讓我糾結了很久,以至于發現了如此坑爹的刪除數組方式.

這里給大家介紹一下m_uAutoReleaseCount這個自動釋放計數的前身.Cocos2d-x這個引擎其實是來源于Cocos2d,而這個引擎是蘋果機專用,也就是用的Object-C,而帶引用計數的指針是Object-C語言層面就支持的東西,在蘋果里面,這個釋放計數其實是布爾值.?.而C++語言層面并不支持釋放計數,也就是帶引用計數的指針,所以只能模擬.這下好了,一模擬就模擬了個我目前為止覺得是不僅廢材還費腦子的變量m_uAutoReleaseCount.我曾經試圖控制他的值,不過引擎會報錯.但是我實在是沒找到有哪里在判斷他的值了.除了那個無關緊要的~CCObject.求高手解答吧!

也就是說,按照內核的自動管理措施,確實可以釋放掉不用的內存,但是,會生成一大堆的野指針.真是不負責任的自動管理.不過通過我簡單的研究,這個自動管理類,確實沒辦法將野指針消除,只能讓系統回收,算是他引擎的缺陷吧.要不然,Cocos2d的開發者也不會叫我們盡量不要用自動釋放.

好啦,重要的分析結束啦!

下面呢,我就把整個自動管理的過程串起來,給大家一個清晰的思路了.

  • 我們首先new一個類出來??CCSprite?*pSprite?=?CCSprite::create(),這個靜態工廠方法里,直接就執行了autorelease操作了.

  • ,這里面的過程就是這樣的:new操作將引用計數初始化為1,釋放計數初始化為0,?autorelease通過幾次操作,將我們的pSprite,也就是他的內存地址存放進了自動釋放池里.然后retain將引用計數加1.這時引用計數為2.這時,我們就可以理解,為什么后面有一個pObject->release()操作了.我們只是想把他加入自動管理,但并不想retain他.于是乎,引用計數還是1.

  • 這時,我們執行addChild(pSprite),將我們的精靈加入節點中,這個操作也會將引用計數加1.來給大家看看代碼.

  • ……………………..

  • ,我只挑重要的函數講,這里執行了一個insertChild操作.

  • void?CCNode::insertChild(CCNode*?child,?int?z)

    {

    ???m_bReorderChildDirty?=?true;

    ???ccArrayAppendObjectWithResize(m_pChildren->data,?child);

    ???child->_setZOrder(z);

    }

  • ,我們上一篇才提到的函數ccArrayAppendObjectWithResize又出現了,他的出現,就意味著retain的出現.我就不繼續粘代碼了,那這里的m_pChildren就一定是一個CCArray的指針了.這時pSprite的引用計數為2.

  • 假設這時我們的游戲中有且僅有一個精靈,也就是我們的pSprite,我們暫時把他看成是玩家,游戲中,玩家是我們主要操作的對象,加入自動釋放后,就有被自動釋放的可能,但是這是我們所不允許的.引擎自然也知道則一點.所以,這時候mainLoop執行一次,pop執行一次,我們當前有自動釋放池,所以clear執行一次.clear中,釋放計數被減1,歸零,然后由于removeAllObjects的執行,我們的玩家pSprite執行一次release,引用計數減由2變成1.然后數組被強行歸零.這時mainLoop再次執行的話,釋放池中的元素個數就為0了(沒有再添加其他的東西).

  • ,這不是坑爹嗎?釋放池就是用來釋放指針的,但是pSprite的引用計數還有1,是不會執行delete?this操作的.你說對了,這就是為什么,我們還能操作玩家的原因,如果這個指針被釋放了,我們豈不是在操作野指針了?那如何控制玩家?

  • 其實說到這里,大家應該明白了.這個自動釋放池,做的事情,僅僅是釋放掉引用計數為1的指針.只要引用計數超過1,那就不會釋放.做的只是將引用計數減一的操作.那我們結束游戲,或者切換場景時,那些引用計數大于1的指針,改如何釋放呢??分析到這里的,我個人也認為,這個內存管理算是比較坑的了.

    仔細想一下,內存泄露的原因是什么,說簡單點,就是只new而不delete.什么情況下會發生這樣的情況呢?比如說,我們的一個射擊游戲,要發射很多子彈,于是我們在一個界面里new很多子彈出來,但是子彈碰撞后不delete掉,以至于子彈越來越多,內存越占越大.然后我們突然切換場景Scene,因為場景的對象消亡了,所以場景的析構函數被執行,自動釋放了他占的內存,但是我們的子彈并沒有執行析構函數,所以一直把空間占著,那段內存就廢掉了,于是乎內存泄露.

    但是我們切換界面的時候,玩家的引用計數為1,并且不再釋放池內了,那該如何釋放?這里,我們就要看下CCNode的析構函數了.

    CCNode::~CCNode(void)

    {

    ????CCLOGINFO("cocos2d:?deallocing"?);

    ……………………………

    ????if(m_pChildren&&?m_pChildren->count()?>?0)

    ????{

    ????????CCObject*child;

    ???????CCARRAY_FOREACH(m_pChildren,?child)

    ????????{

    ????????????CCNode*pChild?=?(CCNode*)?child;

    ????????????if(pChild)

    ????????????{

    ???????????????pChild->m_pParent?=?NULL;

    ????????????}

    ????????}

    ????}

    ????//?children

    ???CC_SAFE_RELEASE(m_pChildren);

    }

    他幫我們完成了這一步.我們的玩家不是在Layer上的么?Layer又在Scene上,當Scene被替換掉時,會自動執行他的析構函數,再執行父類的析構函數,也就是上面這段,這其中的m_pChildren中就保存著指向Layer的指針,他將Layer的父類賦值為空,然后release掉m_pChildren.而這個m_pChildre是指向CCArray的指針,?CCArray是CCObject的子類,初始化時引用計數被加了1,然后autorelease加入自動釋放池.?m_pChildren被初始化為NULL,他是這樣創建的

    void?CCNode::addChild(CCNode?*child,int?zOrder,?int?tag)

    {???

    ???if(?!?m_pChildren?)

    ???{

    ???????this->childrenAlloc();

    }

    }

    ?

    void?CCNode::childrenAlloc(void)

    {

    ???m_pChildren?=?CCArray::createWithCapacity(4);

    ???m_pChildren->retain();

    }

    一來就被retain一次,經過一次pop引用計數為1,所以不會被釋放.而最后的CC_SAFE_RELEASE(m_pChildren),將他的引用計數變為0.執行delete?this操作,進而執行析構函數.

    CCArray::~CCArray()

    {

    ???ccArrayFree(data);

    }

    析構函數里執行了一次釋放操作.

    void?ccArrayFree(ccArray*&?arr)

    {

    ???if(?arr?==?NULL?)?

    ???{

    ???????return;

    ???}

    ?????????ccArrayRemoveAllObjects(arr);

    ?????????

    ?????????free(arr->arr);

    ?????????free(arr);

    ?

    ???arr?=?NULL;

    }

    這里又執行了一個remove操作,這個蒙了我很久的函數ccArrayRemoveAllObjects(arr),他用m_pChildren數組里的成員執行一次release操作,也就是layer->release(),因為我們的layer并沒有手動retain過.所以他的引用計數減1變為0,然后執行delete?this.回收內存.接著,保存layer的這個數組被free掉,然后m_pChildren被free掉,接著賦值為NULL,徹底刪除指針.

    這樣一來,layer就徹底沒有了.我們以此類推,存在layer上的東西,也就是儲存在layer里m_pChildren中的什么CCSprite?,CCMenu,CCLabelTTF等等,都會在界面切換時被徹底刪除掉.所以,內存管理不僅僅只是autorelease做的事情,節點CCNode其實承擔了相當大一部分內存管理工作.相比起來,釋放池做的工作,僅僅是擔心我們使用局部指針變量時,忘記release的一種防范策略.

    不過這也提醒了我們,如果我們new了一個局部的指針,并且手動retain了一下,那就必須在必要的地方手動release他一次,并且兩個操作的次數必須一樣.為什么呢?回顧一下上面分析的就知道了,最后僅僅只是release了一下而已,也就是說在不手動retain的情況下,我們的內存管理,最多能回收掉引用計數為2的指針,如果你手動retain了,那最后的那個release不足以把引用計數減到0,那么就內存泄露了………..

    不過如果你執行的是退出游戲,那就無所謂了,現在的操作系統,都能在程序退出時,將他所占用的內存全部回收掉,就算是你new了一堆東西出來還不delete.

    Cocos2d-x的內存管理到這里就分析完了,雖然沒有我想想的那樣智能,但是也讓我學到很多內存管理的思想.我們下一篇內核分析再見~

    后記:
    ??????? 寫完這篇文章后,我在做開發時又想了一下,其實這個自動釋放池不能算是坑,他的目的是把我們new出來的指針的引用計數釋放到1,從而讓Scene切 換,Layer切換,退出程序時,真正的內存管理,也就是CCNode和CCObject的內存管理能順利吧所有的指針都釋放掉.
    ????????所以總結一下,此內存管理的思路是,用autorelease將指針的釋放計數控制在一定范圍內(最大值是2,autorelease之后必須最大是1),以至于當界面切換,各個類執行remove操作,程序退出等情況下能將占用的內存全部釋放掉.

    轉載于:https://www.cnblogs.com/zhepama/p/3795716.html

    總結

    以上是生活随笔為你收集整理的Cocos2d-x内存管理研究二的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。