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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

cocos2dx标准容器_cocos2dx[3.2](24)——内存管理机制

發(fā)布時(shí)間:2023/12/15 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 cocos2dx标准容器_cocos2dx[3.2](24)——内存管理机制 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

【嘮叨】

整合參考文檔。

【參考】

【內(nèi)存管理機(jī)制】

在3.x版本,Cocos2d-x采用全新的根類?Ref,實(shí)現(xiàn)Cocos2d-x 類對(duì)象的引用計(jì)數(shù)記錄。引擎中的所有類都派生自Ref。

1、引用計(jì)數(shù)

Cocos2d-x 提供引用計(jì)數(shù)管理內(nèi)存。

>?調(diào)用 retain() 方法 ? ? ? ? ? ? :令其引用計(jì)數(shù)增1,表示獲取該對(duì)象的引用權(quán)。

> 調(diào)用 release() 方法 ? ? ? ? ?:在引用結(jié)束的時(shí)候,令其引用計(jì)數(shù)值減1,表示釋放該對(duì)象的引用權(quán)。

> 調(diào)用 autorelease() 方法 :將對(duì)象放入自動(dòng)釋放池。

>?當(dāng)釋放池自身被釋放的時(shí)候,它就會(huì)對(duì)池中的所有對(duì)象執(zhí)行一次release()方法,實(shí)現(xiàn)靈活的垃圾回收。

Cocos2d-x 提供 AutoreleasePool,管理自動(dòng)釋放對(duì)象。

>?當(dāng)釋放池自身被釋放的時(shí)候,它就會(huì)對(duì)池中的所有對(duì)象執(zhí)行一次release()方法。

核心類Ref:實(shí)現(xiàn)了引用計(jì)數(shù)。//

/**

*CCRef.h

**/

class?CC_DLL?Ref

{

public:

void?retain();??????//?保留。引用計(jì)數(shù)+1

void?release();?????//?釋放。引用計(jì)數(shù)-1

Ref*?autorelease();?//?實(shí)現(xiàn)自動(dòng)釋放。

unsigned?int?getReferenceCount()?const;?//被引用次數(shù)

protected:

Ref();??????????//?初始化

public:

virtual?~Ref();?//?析構(gòu)

protected:

unsigned?int?_referenceCount;?//?引用次數(shù)

friend?class?AutoreleasePool;?//?自動(dòng)釋放池

};

/**

*CCRef.cpp

**/

//?節(jié)點(diǎn)被創(chuàng)建時(shí),引用次數(shù)為?1

Ref::Ref()?:?_referenceCount(1)

{

}

void?Ref::retain()

{

CCASSERT(_referenceCount?>?0,?"reference?count?should?greater?than?0");

++_referenceCount;

}

void?Ref::release()

{

CCASSERT(_referenceCount?>?0,?"reference?count?should?greater?than?0");

--_referenceCount;

if?(_referenceCount?==?0)

{

delete?this;

}

}

Ref*?Ref::autorelease()

{

//?將節(jié)點(diǎn)加入自動(dòng)釋放池

PoolManager::getInstance()->getCurrentPool()->addObject(this);

return?this;

}

//

Ref原理分析:

>?當(dāng)一個(gè) Ref 初始化(被new出來時(shí)),_referenceCount = 1;

>?當(dāng)調(diào)用該 Ref 的 retain() 方法時(shí),_referenceCount++;

>?當(dāng)調(diào)用該 Ref 的 release() 方法時(shí),_referenceCount--。

>?若??_referenceCount 減后為0,則 delete 該 Ref。

2、retain() 和 release() 使用

下面一段簡單的例子來學(xué)習(xí) retain() 和 release() 的使用。//

TestObject*?obj1?=?new?TestObject("testobj1");

CCLOG("obj1?referenceCount=%d",obj1->getReferenceCount());

obj1->retain();

CCLOG("obj1?referenceCount=%d",obj1->getReferenceCount());

obj1->release();

CCLOG("obj1?referenceCount=%d",obj1->getReferenceCount());

obj1->release();

//

控制臺(tái)顯示的日志如下:cocos2d: TestObject:testobj1 is created

cocos2d: obj1 referenceCount=1

cocos2d: obj1 referenceCount=2

cocos2d: obj1 referenceCount=1

cocos2d: TestObject:testobj1 is destroyed

通過例子和打印結(jié)果可以看到:

>?obj1對(duì)象創(chuàng)建后,引用計(jì)數(shù)為1;

>?執(zhí)行一次retain()后,引用計(jì)數(shù)為2;

>?執(zhí)行一次release()后,引用計(jì)數(shù)回到1;

>?再執(zhí)行一次release()后,對(duì)象會(huì)被釋放掉。

因此:

>?我們可以調(diào)用retain()方法,令其引用計(jì)數(shù)增1,表示獲取該對(duì)象的引用權(quán);

>?在引用結(jié)束的時(shí)候調(diào)用release()方法,令其引用計(jì)數(shù)值減1,表示釋放該對(duì)象的引用權(quán)。

>?直到對(duì)象的引用計(jì)數(shù)為0,釋放該對(duì)象。

3、autorelease() 使用

同樣一段簡單的例子來學(xué)習(xí)autorelease的使用,代碼如下://

TestObject*?obj?=?new?TestObject("testobj");

CCLOG("obj?referenceCount=%d",obj->getReferenceCount());

obj->autorelease();

CCLOG("obj?is?add?in?currentpool?%s",PoolManager::getInstance()->getCurrentPool()->contains(obj)?"true":"false");

CCLOG("obj?referenceCount=%d",obj->getReferenceCount());

obj->retain();

CCLOG("obj?referenceCount=%d",obj->getReferenceCount());

obj->release();

CCLOG("obj?referenceCount=%d",obj->getReferenceCount());

//obj?in?current?pool?will?be?release

Director::getInstance()->replaceScene(this);

//

控制臺(tái)顯示的日志如下:cocos2d: TestObject:testobj is created

cocos2d: obj referenceCount=1

cocos2d: obj is add in currentpool true

cocos2d: obj referenceCount=1

cocos2d: obj referenceCount=2

cocos2d: obj referenceCount=1

...

cocos2d: TestObject:testobj is destroyed

通過代碼和打印結(jié)果,我們可以看到:

>?obj對(duì)象創(chuàng)建后,引用計(jì)數(shù)為1;

>?執(zhí)行一次autorelease()后,obj對(duì)象被加入到當(dāng)前的自動(dòng)釋放池。

>?obj對(duì)象的引用計(jì)數(shù)值并沒有減1。

>?但是在下一幀開始前,當(dāng)前的自動(dòng)釋放池會(huì)被回收掉,并對(duì)自動(dòng)釋放池中的所有對(duì)象執(zhí)行一次release()操作。

>?當(dāng)對(duì)象的引用計(jì)數(shù)為0時(shí),對(duì)象會(huì)被釋放掉。

>?obj對(duì)象執(zhí)行autorelease()后,我們對(duì)其執(zhí)行了一組retain()和release()操作。

>?此時(shí)obj對(duì)象的引用計(jì)數(shù)為1,在場景切換后,當(dāng)前的自動(dòng)釋放池被回收,

>?obj對(duì)象執(zhí)行一次release()操作引用計(jì)數(shù)減為0時(shí),對(duì)象會(huì)被釋放掉。

注意:autorelease()只有在自動(dòng)釋放池被釋放時(shí)才會(huì)進(jìn)行一次釋放操作,如果對(duì)象釋放的次數(shù)超過了應(yīng)有的次數(shù),則這個(gè)錯(cuò)誤在調(diào)用autorelease()時(shí)并不會(huì)被發(fā)現(xiàn),只有當(dāng)自動(dòng)釋放池被釋放時(shí)(通常也就是游戲的每一幀結(jié)束時(shí)),游戲才會(huì)崩潰。在這種情況下,定位錯(cuò)誤就變得十分困難了。

例如,在游戲中,一個(gè)對(duì)象含有1個(gè)引用計(jì)數(shù),但是卻被調(diào)用了兩次autorelease()。在第二次調(diào)用autorelease()時(shí),游戲會(huì)繼續(xù)執(zhí)行這一幀,結(jié)束游戲時(shí)才會(huì)崩潰,很難及時(shí)找到出錯(cuò)的地點(diǎn)。

因此,我們建議在開發(fā)過程中應(yīng)該避免濫用autorelease(),只在工廠方法等不得不用的情況下使用,盡量以release()來釋放對(duì)象引用。

4、AutoreleasePool類 使用

Cocos2d-x提供AutoreleasePool,管理自動(dòng)釋放對(duì)象。

下面一段簡單的例子講解AutoreleasePool的使用,代碼如下://

TestObject*?obj2?=?new?TestObject("testobj2");

CCLOG("obj2?referenceCount=%d",obj2->getReferenceCount());

//use?AutoreleasePool

{

AutoreleasePool?pool;

obj2->retain();

CCLOG("obj2?referenceCount=%d",obj2->getReferenceCount());

obj2->release();

CCLOG("obj2?referenceCount=%d",obj2->getReferenceCount());

obj2->autorelease();

CCLOG("obj2?is?add?in?pool?%s",pool.contains(obj2)?"true":"false");

TestObject?*obj3?=?new?TestObject("testobj3");

obj3->autorelease();

CCLOG("obj3?is?add?in?pool?%s",pool.contains(obj3)?"true":"false");

}

//

控制臺(tái)輸出日志如下:cocos2d: TestObject:testobj2 is created

cocos2d: obj2 referenceCount=1

cocos2d: obj2 referenceCount=2

cocos2d: obj2 referenceCount=1

cocos2d: obj2 is add in pool true

cocos2d: TestObject:testobj3 is created

cocos2d: obj3 is add in pool true

cocos2d: TestObject:testobj2 is destroyed

cocos2d: TestObject:testobj3 is destroyed

通過代碼和輸出結(jié)果,可以看到:

>?創(chuàng)建了一個(gè)obj2對(duì)象,此時(shí)obj2對(duì)象的引用計(jì)數(shù)為1。

>?接著創(chuàng)建了一個(gè)自動(dòng)釋放池,對(duì)obj2對(duì)象執(zhí)行retain()和release()操作后,執(zhí)行autorelease()操作,此時(shí)obj2對(duì)象被加入到當(dāng)前新建的自動(dòng)釋放池中。

>?接著新建了obj3對(duì)象,并執(zhí)行autorelease()操作。同樣obj3也被加入到當(dāng)前新建的自動(dòng)釋放池中。

>?在代碼塊結(jié)束后,自動(dòng)釋放池被回收,加入自動(dòng)釋放池中的obj2和obj3執(zhí)行release()操作,引用計(jì)數(shù)減為0,被釋放銷毀。

我們可以自己創(chuàng)建AutoreleasePool,管理對(duì)象的autorelease。

我們已經(jīng)知道,調(diào)用了autorelease()方法的對(duì)象(下面簡稱"autorelease對(duì)象"),將會(huì)在自動(dòng)釋放池釋放的時(shí)候被釋放一次。雖然,Cocos2d-x已經(jīng)保證每一幀結(jié)束后釋放一次釋放池,并在下一幀開始前創(chuàng)建一個(gè)新的釋放池,但是我們也應(yīng)該考慮到釋放池本身維護(hù)著一個(gè)將要執(zhí)行釋放操作的對(duì)象列表,如果在一幀之內(nèi)生成了大量的autorelease對(duì)象,將會(huì)導(dǎo)致釋放池性能下降。因此,在生成autorelease對(duì)象密集的區(qū)域(通常是循環(huán)中)的前后,我們最好可以手動(dòng)創(chuàng)建并釋放一個(gè)回收池。

例如://

//?example?of?using?temple?autorelease?pool

{

AutoreleasePool?pool2;

char?name[20];

for?(int?i?=?0;?i?

{

snprintf(name,?20,?"object%d",?i);

TestObject?*tmpObj?=?new?TestObject(name);

tmpObj->autorelease();

}

}

//

總結(jié):

>?autorelease()的實(shí)質(zhì)是將對(duì)象加入自動(dòng)釋放池,對(duì)象的引用計(jì)數(shù)不會(huì)立刻減1,在自動(dòng)釋放池被回收時(shí)對(duì)象執(zhí)行release()。

> autorelease()并不是毫無代價(jià)的,其背后的釋放池機(jī)制同樣需要占用內(nèi)存和CPU資源。

>?過多的使用autorelease()會(huì)增加自動(dòng)釋放池的管理和釋放池維護(hù)對(duì)象存取釋放的支出。

>?在內(nèi)存和CPU資源本就不足的程序中使得系統(tǒng)資源更加緊張。

>?此時(shí)就需要我們合理創(chuàng)建自動(dòng)釋放池管理對(duì)象autorelease。

>?不用的對(duì)象推薦使用release()來釋放對(duì)象引用,立即回收。

5、特殊內(nèi)存管理

5.1、工廠方法 create()

在Cocos2d-x中,提供了大量的工廠方法創(chuàng)建對(duì)象。仔細(xì)看你會(huì)發(fā)現(xiàn),這些對(duì)象都是自動(dòng)釋放的。

下面以 Label 的 create 方法為例,代碼如下://

Label*?Label::create()

{

auto?ret?=?new?Label();

if?(ret)

{

ret->autorelease();

}

return?ret;

}

//

我們可以發(fā)現(xiàn),創(chuàng)建了一個(gè)Label的對(duì)象,并對(duì)該對(duì)象執(zhí)行autorelease()。表示該對(duì)象是自動(dòng)釋放的。細(xì)心的你會(huì)發(fā)放Layer/Scene/Sprite等類的 create() 方法都相同。

使用工廠方法創(chuàng)建對(duì)象時(shí),雖然引用計(jì)數(shù)也為1,但是由于對(duì)象已經(jīng)被放入了釋放池,因此調(diào)用者沒有對(duì)該對(duì)象的引用權(quán),除非我們?nèi)藶榈卣{(diào)用了retain()來獲取引用權(quán),否則,不需要主動(dòng)釋放對(duì)象。

5.2、Node 的 addChild() / removeChild 方法

在Cocos2d-x中,所有繼承自Node類,在調(diào)用 addChild 方法添加子節(jié)點(diǎn)時(shí),自動(dòng)調(diào)用了retain。 對(duì)應(yīng)的通過?removeChild,移除子節(jié)點(diǎn)時(shí),自動(dòng)調(diào)用了release。

調(diào)用addChild方法添加子節(jié)點(diǎn),節(jié)點(diǎn)對(duì)象執(zhí)行retain。子節(jié)點(diǎn)被加入到節(jié)點(diǎn)容器中,父節(jié)點(diǎn)銷毀時(shí),會(huì)銷毀節(jié)點(diǎn)容器釋放子節(jié)點(diǎn)。對(duì)子節(jié)點(diǎn)執(zhí)行release。如果想提前移除子節(jié)點(diǎn)我們可以調(diào)用removeChild。

在Cocos2d-x內(nèi)存管理中,大部分情況下我們通過調(diào)用 addChild/removeChild 的方式自動(dòng)完成了retain,release調(diào)用。不需再調(diào)用retain,release。

【內(nèi)存優(yōu)化】

1、內(nèi)存優(yōu)化原理

為優(yōu)化應(yīng)用內(nèi)存使用,開發(fā)人員首先應(yīng)該知什么最耗應(yīng)用內(nèi)存,答案就是紋理! 紋理幾乎會(huì)占據(jù)90%應(yīng)用內(nèi)存。所以盡量最小化應(yīng)用的紋理內(nèi)存使用,否則應(yīng)用很有可能會(huì)因?yàn)榈蛢?nèi)存而崩潰。

本節(jié)介紹Cocos2d-x游戲通用的兩條內(nèi)存優(yōu)化原理指導(dǎo)。

1.1、認(rèn)識(shí)瓶頸尋找方案

什么樣的紋理最耗應(yīng)用內(nèi)存?或這些紋理會(huì)消耗多少內(nèi)存?

當(dāng)然這個(gè)不用手動(dòng)計(jì)算,只需猜測。工具在這里已經(jīng)準(zhǔn)備好了,使用的是蘋果的工具“Allocation & Leaks”。你可以在Xcode中長按“Run”命令,選擇“ Profile ”來啟動(dòng)這兩個(gè)工具。

如下所示:

使用Allocation工具可以監(jiān)控應(yīng)用的內(nèi)存使用,使用Leaks工具可以觀察內(nèi)存的泄漏情況。

此外還可用一些代碼獲取游戲內(nèi)存使用的其他信息。

如下所示://

Sprite*?bg?=?Sprite::create("HelloWorld.png");

bg->setPosition(240,?160);

this->addChild(bg);

CCLOG("%s",?Director::getInstance()->getTextureCache()->getCachedTextureInfo().c_str());

//

調(diào)用這個(gè)代碼后,游戲便會(huì)在DEBUG模式運(yùn)行,這時(shí)你會(huì)在Xcode控制臺(tái)窗口看到一些格式工整的日志信息。//

cocos2d:?"****/HelloWorld.png"?rc=2?id=3?480?x?320?@?32?bpp?=>?600?KB

"/cc_fps_p_w_picpaths"?rc=5?id=2?999?x?54?@?16?bpp?=>?105?KB

TextureCache?dumpDebugInfo:?2?textures,?for?705?KB?(0.69?MB)

//

從上可以看到會(huì)顯示紋理的名稱、引用計(jì)數(shù)、ID、大小及每像素的位數(shù)。最重要的是會(huì)顯示內(nèi)存的使用情況。如“cc_fps_p_w_picpaths”指消耗了105KB內(nèi)存,而“HelloWorld.png”消耗了600KB內(nèi)存。

1.2、切勿過度優(yōu)化

這是一個(gè)通用的優(yōu)化規(guī)則。在優(yōu)化過程中,應(yīng)該做一些權(quán)衡取舍。因?yàn)橛袝r(shí)候圖像質(zhì)量和圖像內(nèi)存使用是處于兩級(jí)的狀態(tài)。千萬不要過度優(yōu)化!

2、內(nèi)存優(yōu)化水平

在此將ccos2d-x內(nèi)存優(yōu)化分為:三個(gè)等級(jí)。

每個(gè)等級(jí)都有不同的說明,策略也有點(diǎn)不一樣。

2.1、客戶端等級(jí)

這是最重要的的優(yōu)化等級(jí)。因?yàn)槲覀円贑ocos2d-x引擎頂層編譯游戲,引擎自身會(huì)提供一些優(yōu)化選項(xiàng)。 在這個(gè)等級(jí)我們可以進(jìn)行大部分優(yōu)化。簡而言之,我們可以優(yōu)化紋理、音頻、字體及粒子的內(nèi)存使用。

第一:看紋理優(yōu)化,為了優(yōu)化紋理內(nèi)存使用,必須知道什么因素對(duì)紋理內(nèi)存使用的影響最大。主要有3個(gè)因素會(huì)影響紋理內(nèi)存,即紋理格式(壓縮還是非壓縮)、顏色深度和大小。我們可以使用PVR格式紋理減少內(nèi)存使用。推薦紋理格式為pvr.ccz。紋理使用的每種顏色位數(shù)越多,圖像質(zhì)量越好,但是越耗內(nèi)存。所以我們可以使用顏色深度為RGB4444的紋理代替RGB8888,這樣內(nèi)存消耗會(huì)降低一半。此外超大的紋理也會(huì)導(dǎo)致內(nèi)存相關(guān)問題。所以最好使用中等大小的紋理。

第二:音頻優(yōu)化,3個(gè)因素會(huì)影響音頻文件的內(nèi)存使用,即音頻文件數(shù)據(jù)格式、比特率及采樣率。推薦使用MP3數(shù)據(jù)格式的音頻文件,因?yàn)锳ndroid平臺(tái)和iOS平臺(tái)均支持MP3格式,此外MP3格式經(jīng)過壓縮和硬件加速。背景音樂文件大小應(yīng)該低于800KB,最簡單的方法就是減少背景音樂時(shí)間然后重復(fù)播放。音頻文件采樣率大約在96-128kbps為佳,比特率44kHz就夠了。

第三:字體和粒子優(yōu)化,在此有兩條小提示:使用BMFont字體顯示游戲分?jǐn)?shù)時(shí),請(qǐng)盡可能使用最少數(shù)量的文字。例如只想要顯示單位數(shù)的數(shù)字,你可以移除所有字母。至于粒子,可以通過減少粒子數(shù)來降低內(nèi)存使用。

2.2、引擎等級(jí)

需要 OpenGL ES 及游戲引擎高手。

2.3、C++語言等級(jí)

在這個(gè)等級(jí)中,建議是編寫無內(nèi)存泄露代碼。遵循Cocos2d-x內(nèi)置的內(nèi)存管理原則,盡量避免內(nèi)存泄露。

3.、提示和技巧

(1) ? ?一幀一幀載入游戲資源

(2) ? ?減少繪制調(diào)用,使用“Auto-batching”自動(dòng)批處理。

(3) ? ?載入紋理時(shí)按照從大到小的順序

(4) ? ?避免高峰內(nèi)存使用

(5) ? ?使用載入屏幕預(yù)載入游戲資源

(6) ? ?需要時(shí)釋放空閑資源

(7) ? ?收到內(nèi)存警告后釋放緩存資源.

(8) ? ?使用紋理打包器優(yōu)化紋理大小、格式、顏色深度等

(9) ? ?使用JPG格式要謹(jǐn)慎!

(10) ?請(qǐng)使用RGB4444顏色深度16位紋理

(11) ?請(qǐng)使用NPOT紋理,不要使用POT紋理

(12) ?避免載入超大紋理

(13) ?推薦1024*1024 NPOT pvr.ccz紋理集,而不要采用RAW PNG紋理

總結(jié)

以上是生活随笔為你收集整理的cocos2dx标准容器_cocos2dx[3.2](24)——内存管理机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。